diff -r 3b4c4e6862b6 core.startup/src/org/netbeans/core/startup/layers/BinaryFS.java --- a/core.startup/src/org/netbeans/core/startup/layers/BinaryFS.java Wed Nov 24 13:31:16 2010 +0100 +++ b/core.startup/src/org/netbeans/core/startup/layers/BinaryFS.java Wed Nov 24 16:37:42 2010 +0100 @@ -372,6 +372,7 @@ // Attributes implementation: /** Get the file attribute with the specified name. */ + @Override public Object getAttribute(String attrName) { initialize(); AttrImpl attr = attrs.get(attrName); @@ -379,6 +380,19 @@ attr = attrs.get(attrName.substring(6)); return attr == null ? null : attr.getType(this); } + if (attr == null && attrName.startsWith("raw:")) { // NOI18N + attr = attrs.get(attrName.substring(4)); + try { + if (attr != null && attr.index == 10) { + return attr.methodValue(attr.value, this, attrName).getMethod(); + } + if (attr != null && attr.index == 11) { + return attr.getType(this); + } + } catch (Exception ex) { + } + return null; + } if (attr == null && attrName.equals("layers")) { // NOI18N return getLayersAttr(); } diff -r 3b4c4e6862b6 openide.filesystems/apichanges.xml --- a/openide.filesystems/apichanges.xml Wed Nov 24 13:31:16 2010 +0100 +++ b/openide.filesystems/apichanges.xml Wed Nov 24 16:37:42 2010 +0100 @@ -49,6 +49,28 @@ Filesystems API + + + setAttribute("methodvalue:attrname", method) and "newvalue:" + + + + + +

+ You can use prefix "methodvalue:" to set + an attribute of type Method. + When the attribute is queried (without the prefix), the + method is called as is common in + XMLFileSystem + attributes. You can also use newvalue: prefix + for attribute of type + Class. +

+
+ + +
FileObject.createAndOpen diff -r 3b4c4e6862b6 openide.filesystems/arch.xml --- a/openide.filesystems/arch.xml Wed Nov 24 13:31:16 2010 +0100 +++ b/openide.filesystems/arch.xml Wed Nov 24 16:37:42 2010 +0100 @@ -454,11 +454,31 @@ --> -Yes, attributes can contain also dynamic values associated with keys (methodvalue and newvalue). + +Many FileSystem +implementations support special form of arguments for their +setAttribute method. One can use +prefix methodvalue: or newvalue +to store references to +Method or +Class respectively. The +getAttribute then behaves like +XMLFileSystem's +methodvalue and newvalue attributes: + + + +It is possible to prefix call to FileObject.getAttribute +with raw: prefix to evaluate the attribute without instantiating it +(e.g. get Method or +Class values from +methodvalue and newvalue attributes. This API +is not intended for public use at present and can change in future. + diff -r 3b4c4e6862b6 openide.filesystems/manifest.mf --- a/openide.filesystems/manifest.mf Wed Nov 24 13:31:16 2010 +0100 +++ b/openide.filesystems/manifest.mf Wed Nov 24 16:37:42 2010 +0100 @@ -2,5 +2,5 @@ OpenIDE-Module: org.openide.filesystems OpenIDE-Module-Localizing-Bundle: org/openide/filesystems/Bundle.properties OpenIDE-Module-Layer: org/openide/filesystems/resources/layer.xml -OpenIDE-Module-Specification-Version: 7.42 +OpenIDE-Module-Specification-Version: 7.43 diff -r 3b4c4e6862b6 openide.filesystems/src/org/openide/filesystems/AbstractFileObject.java --- a/openide.filesystems/src/org/openide/filesystems/AbstractFileObject.java Wed Nov 24 13:31:16 2010 +0100 +++ b/openide.filesystems/src/org/openide/filesystems/AbstractFileObject.java Wed Nov 24 16:37:42 2010 +0100 @@ -327,7 +327,7 @@ /** performance hack */ final Object getAttribute(String attrName, String path) { - return getAbstractFileSystem().attr.readAttribute(path, attrName); + return XMLMapAttr.readAttribute(this, getAbstractFileSystem().attr, path, attrName); } /* Set the file attribute with the specified name. @@ -348,7 +348,7 @@ Object oldValue = null; //FileSystem fs = getAbstractFileSystem (); - //if (fs.isReadOnly()) + //if (fs.isReadOnly()) XMLFileSystemTestHid.java:934 // throw new FSException(NbBundle.getMessage(AbstractFileObject.class, "EXC_FSisRO", fs.getDisplayName ()); // NOI18N if (fire) { oldValue = getAttribute(attrName); diff -r 3b4c4e6862b6 openide.filesystems/src/org/openide/filesystems/DefaultAttributes.java --- a/openide.filesystems/src/org/openide/filesystems/DefaultAttributes.java Wed Nov 24 13:31:16 2010 +0100 +++ b/openide.filesystems/src/org/openide/filesystems/DefaultAttributes.java Wed Nov 24 16:37:42 2010 +0100 @@ -70,6 +70,7 @@ import java.util.TreeSet; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; +import org.openide.filesystems.AbstractFileSystem.Attr; import org.openide.util.Enumerations; import org.openide.util.NbBundle; import org.openide.util.Utilities; diff -r 3b4c4e6862b6 openide.filesystems/src/org/openide/filesystems/FileUtil.java --- a/openide.filesystems/src/org/openide/filesystems/FileUtil.java Wed Nov 24 13:31:16 2010 +0100 +++ b/openide.filesystems/src/org/openide/filesystems/FileUtil.java Wed Nov 24 16:37:42 2010 +0100 @@ -54,6 +54,7 @@ import java.lang.ref.Reference; import java.lang.ref.SoftReference; import java.lang.ref.WeakReference; +import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; @@ -74,6 +75,7 @@ import java.util.WeakHashMap; import java.util.concurrent.Callable; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.jar.JarEntry; import java.util.jar.JarInputStream; import java.util.logging.Level; @@ -1101,14 +1103,21 @@ continue; } - Object value = source.getAttribute(key); + AtomicBoolean isRawValue = new AtomicBoolean(); + Object value = XMLMapAttr.getRawAttribute(source, key, isRawValue); // #132801 and #16761 - don't set attributes where value is // instance of VoidValue because these attributes were previously written // by mistake in code. So it should happen only if you import some // settings from old version. if (value != null && !(value instanceof MultiFileObject.VoidValue)) { - dest.setAttribute(key, value); + if (isRawValue.get() && value instanceof Method) { + dest.setAttribute("methodvalue:" + key, value); // NOI18N + } else if (isRawValue.get() && value instanceof Class) { + dest.setAttribute("newvalue:" + key, value); // NOI18N + } else { + dest.setAttribute(key, value); + } } } } diff -r 3b4c4e6862b6 openide.filesystems/src/org/openide/filesystems/XMLMapAttr.java --- a/openide.filesystems/src/org/openide/filesystems/XMLMapAttr.java Wed Nov 24 13:31:16 2010 +0100 +++ b/openide.filesystems/src/org/openide/filesystems/XMLMapAttr.java Wed Nov 24 16:37:42 2010 +0100 @@ -61,6 +61,7 @@ import java.util.Set; import java.util.SortedSet; import java.util.TreeSet; +import java.util.concurrent.atomic.AtomicBoolean; import org.openide.util.SharedClassObject; import org.openide.util.Utilities; import org.openide.util.io.NbMarshalledObject; @@ -149,6 +150,29 @@ return new Attr(index, value); } + static Object getRawAttribute(FileObject fo, String name, AtomicBoolean ab) { + Object raw = fo.getAttribute("raw:" + name); // NOI18N + if (raw != null) { + if (ab != null) { + ab.set(true); + } + return raw; + } + if (ab != null) { + ab.set(false); + } + return fo.getAttribute(name); + } + private static ThreadLocal ATTR_FOR = new ThreadLocal(); + static Object readAttribute(FileObject forFO, AbstractFileSystem.Attr attr, String path, String attrName) { + FileObject prev = ATTR_FOR.get(); + try { + ATTR_FOR.set(forFO); + return attr.readAttribute(path, attrName); + } finally { + ATTR_FOR.set(prev); + } + } /** According to name of attribute returns attribute as object * @param p1 is name of attribute * @return attribute, which is hold in XMLMapAttr.Attr or null if such attribute doesn`t exist or isn`t able to construct form String representation @@ -186,7 +210,7 @@ /** implementation of Map.get. But fires Exception to have chance in * DefaultAttributes to catch and annotate*/ Object getAttribute(Object attrName) throws Exception { - return getAttribute(attrName, null); + return getAttribute(attrName, new Object[] { ATTR_FOR.get(), attrName }); } private Object getAttribute(Object attrName, Object[] params) @@ -204,12 +228,24 @@ if (attr == null && origAttrName.startsWith("class:")) { // NOI18N attr = (Attr) map.get(origAttrName.substring(6)); retVal = attr != null ? attr.getType(params) : null; + } else if (attr == null && origAttrName.startsWith("raw:")) { // NOI18N + attr = (Attr) map.get(origAttrName.substring(4)); + if (attr != null && attr.keyIndex == 9) { + return attr.methodValue(attr.value, params).getMethod(); + } + if (attr != null && attr.keyIndex == 12) { + return attr.getType(params); + } } else { - try { - retVal = (attr == null) ? attr : attr.get(params); - } catch (Exception e) { - ExternalUtil.annotate(e, "attrName = " + attrName); //NOI18N - throw e; + if (keyValuePair[1] instanceof ModifiedAttribute) { + return attr; + } else { + try { + retVal = (attr == null) ? attr : attr.get(params); + } catch (Exception e) { + ExternalUtil.annotate(e, "attrName = " + attrName); //NOI18N + throw e; + } } } @@ -244,8 +280,22 @@ Object[] keyValuePair = ModifiedAttribute.translateInto((String) p1, p2); String key = (String) keyValuePair[0]; Object value = keyValuePair[1]; - Object toStore = ((value == null) || value instanceof Attr) ? value : new Attr(value); - + Object toStore; + if (value == null) { + toStore = null; + } else if (value instanceof Attr) { + toStore = value; + } else if (value instanceof Method && key.startsWith("methodvalue:")) { // NOI18N + Method m = (Method)value; + key = key.substring("methodvalue:".length()); // NOI18N + toStore = new Attr("methodvalue", m.getDeclaringClass().getName() + '.' + m.getName()); // NOI18N + } else if (value instanceof Class && key.startsWith("newvalue:")) { // NOI18N + Class c = (Class)value; + key = key.substring("newvalue:".length()); // NOI18N + toStore = new Attr("newvalue", c.getName()); // NOI18N + } else { + toStore = new Attr(value); + } if (decode) { key = Attr.decode(key).intern(); } @@ -621,19 +671,11 @@ } /** - * Constructs new attribute as Object. Used for static creation from literal or serialValue. - * @return new attribute as Object - */ - private Object get() throws Exception { - return getObject(null); //getObject is ready to aobtain null - } - - /** * Constructs new attribute as Object. Used for dynamic creation: methodvalue . * @param objs has sense only for methodvalue invocation; and only 2 parametres will be used *@return new attribute as Object */ - private Object get(Object[] objs) throws Exception { + final Object get(Object[] objs) throws Exception { return getObject(objs); } diff -r 3b4c4e6862b6 openide.filesystems/test/unit/src/org/openide/filesystems/AttributesTestHidden.java --- a/openide.filesystems/test/unit/src/org/openide/filesystems/AttributesTestHidden.java Wed Nov 24 13:31:16 2010 +0100 +++ b/openide.filesystems/test/unit/src/org/openide/filesystems/AttributesTestHidden.java Wed Nov 24 16:37:42 2010 +0100 @@ -47,6 +47,7 @@ import java.util.*; import java.io.*; +import java.lang.reflect.Method; /** * @@ -284,6 +285,59 @@ assertTrue (TEST_ERR,testedFS != null); }*/ + public void testFileUtilCopyAttributes() throws Exception { + assertTrue(TEST_ERR, testedFS != null); + if (testedFS.isReadOnly()) { + return; + } + + File f = new File(getWorkDir(), "sample.xml"); + FileOutputStream fos = new FileOutputStream(f); + fos.write(("" + + "" + + "" + + "" + + "" + + "" + + " " + + " " + + "" + ).getBytes()); + fos.close(); + + XMLFileSystem xfs = new XMLFileSystem(f.toURI().toURL()); + FileObject template = xfs.findResource("Templates/Other/special"); + assertNotNull("template found", template); + FileObject foTested = testedFS.getRoot().createData("copiedTemplate"); + FileUtil.copyAttributes(template, foTested); + assertEquals("template copied too", Boolean.TRUE, foTested.getAttribute("temp")); + assertEquals("instantiatingIterator called", "Hello ii@copiedTemplate", foTested.getAttribute("ii")); + } + + public static String hello(FileObject obj, String attr) { + return "Hello " + attr + "@" + obj.getNameExt(); + } + + public void testSetMethodGetResult() throws Exception { + assertTrue(TEST_ERR, testedFS != null); + if (testedFS.isReadOnly()) { + return; + } + + FileObject foTested = testedFS.getRoot().createData("copiedTemplate"); + Method m = AttributesTestHidden.class.getDeclaredMethod("hello", FileObject.class, String.class); + foTested.setAttribute("methodvalue:ii", m); + + assertEquals("instantiatingIterator called", "Hello ii@copiedTemplate", foTested.getAttribute("ii")); + } + + public static final class Data { + static int cnt; + + public Data() { + cnt++; + } + } // end of Data } diff -r 3b4c4e6862b6 openide.filesystems/test/unit/src/org/openide/filesystems/XMLFileSystemTestHid.java --- a/openide.filesystems/test/unit/src/org/openide/filesystems/XMLFileSystemTestHid.java Wed Nov 24 13:31:16 2010 +0100 +++ b/openide.filesystems/test/unit/src/org/openide/filesystems/XMLFileSystemTestHid.java Wed Nov 24 16:37:42 2010 +0100 @@ -61,7 +61,6 @@ import java.util.Map; import java.util.jar.JarEntry; import java.util.jar.JarOutputStream; -import java.util.zip.ZipEntry; import org.openide.util.Enumerations; public class XMLFileSystemTestHid extends TestBaseHid { @@ -900,7 +899,42 @@ assertAttr("Imutable value is still nochange", nochange, "value", "nochange"); assertEquals("No change in this attribute: " + no.events, 0, no.events.size()); - } + } + + public void testFileUtilCopyAttributesOnOwnLayer() throws Exception { + File f = new File(getWorkDir(), "sample.xml"); + FileOutputStream fos = new FileOutputStream(f); + fos.write(("" + + "" + + "" + + "" + + "" + + "" + + " " + + " " + + " " + + "" + ).getBytes()); + fos.close(); + + File r = new File(getWorkDir(), "root"); + r.mkdirs(); + LocalFileSystem target = new LocalFileSystem(); + target.setRootDirectory(r); + + FileSystem source = FileSystemFactoryHid.createXMLSystem(getName(), this, f.toURI().toURL()); + FileObject template = source.findResource("Templates/Other/special"); + assertNotNull("template found", template); + FileObject foTested = target.getRoot().createData("copiedTemplate"); + FileUtil.copyAttributes(template, foTested); + assertEquals("template copied too", Boolean.TRUE, foTested.getAttribute("temp")); + assertEquals("instantiatingIterator called", "Hello ii@copiedTemplate", foTested.getAttribute("ii")); + assertEquals("No data instantiated", 0, AttributesTestHidden.Data.cnt); + Object newV = foTested.getAttribute("jj"); + assertNotNull("Value created", newV); + assertEquals(AttributesTestHidden.Data.class, newV.getClass()); + assertEquals("One value instantiated", 1, AttributesTestHidden.Data.cnt); + } private static Image icon;