diff --git a/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/resources/layer.xml b/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/resources/layer.xml --- a/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/resources/layer.xml +++ b/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/resources/layer.xml @@ -229,6 +229,7 @@ + diff --git a/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/wizard/winsys/NewTCIterator.java b/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/wizard/winsys/NewTCIterator.java --- a/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/wizard/winsys/NewTCIterator.java +++ b/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/wizard/winsys/NewTCIterator.java @@ -185,6 +185,14 @@ Logger.getLogger(NewTCIterator.class.getName()).log(Level.INFO, null, ex); actionLessTC = false; } + boolean propertiesPersistence; + try { + SpecificationVersion current = model.getModuleInfo().getDependencyVersion("org.netbeans.modules.settings"); + propertiesPersistence = current.compareTo(new SpecificationVersion("1.18")) >= 0; // NOI18N + } catch (IOException ex) { + Logger.getLogger(NewTCIterator.class.getName()).log(Level.INFO, null, ex); + propertiesPersistence = false; + } Map replaceTokens = new HashMap(); @@ -233,11 +241,16 @@ fileChanges.add(fileChanges.addModuleDependency("org.openide.util")); //NOI18N fileChanges.add(fileChanges.addModuleDependency("org.openide.awt")); //NOI18N fileChanges.add(fileChanges.addModuleDependency("org.jdesktop.layout")); //NOI18N + if (propertiesPersistence) { + fileChanges.add(fileChanges.addModuleDependency("org.netbeans.modules.settings")); //NOI18N + } // x. generate java classes final String tcName = getRelativePath(moduleInfo.getSourceDirectoryPath(), packageName, name, "TopComponent.java"); //NOI18N - FileObject template = CreatedModifiedFiles.getTemplate("templateTopComponent.java");//NOI18N + FileObject template = CreatedModifiedFiles.getTemplate( + propertiesPersistence ? "templateTopComponentAnno.java" : "templateTopComponent.java" //NOI18N + ); fileChanges.add(fileChanges.createFileWithSubstitutions(tcName, template, replaceTokens)); // x. generate java classes final String tcFormName = getRelativePath(moduleInfo.getSourceDirectoryPath(), packageName, diff --git a/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/wizard/winsys/templateTopComponentAnno.javx b/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/wizard/winsys/templateTopComponentAnno.javx new file mode 100644 --- /dev/null +++ b/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/wizard/winsys/templateTopComponentAnno.javx @@ -0,0 +1,128 @@ +<#assign licenseFirst = "/*"> +<#assign licensePrefix = " * "> +<#assign licenseLast = " */"> +<#include "../Licenses/license-${project.license}.txt"> + +package ${PACKAGENAME}; + +import java.util.logging.Logger; +import org.openide.util.NbBundle; +import org.openide.windows.TopComponent; +import org.openide.windows.WindowManager; +${COMMENTICON}import org.openide.util.Utilities; + +/** + * Top component which displays something. + */ +@org.netbeans.api.settings.ConvertAsProperties( + dtd="-//${PACKAGENAME}//${TEMPLATENAME}//EN", + autostore=false +) +public final class ${TEMPLATENAME}TopComponent extends TopComponent { + + private static ${TEMPLATENAME}TopComponent instance; + /** path to the icon used by the component and its open action */ +${COMMENTICON} static final String ICON_PATH = "${ICONPATH}"; + + private static final String PREFERRED_ID = "${TEMPLATENAME}TopComponent"; + + public ${TEMPLATENAME}TopComponent() { + initComponents(); + setName(NbBundle.getMessage(${TEMPLATENAME}TopComponent.class, "CTL_${TEMPLATENAME}TopComponent")); + setToolTipText(NbBundle.getMessage(${TEMPLATENAME}TopComponent.class, "HINT_${TEMPLATENAME}TopComponent")); +${COMMENTICON} setIcon(Utilities.loadImage(ICON_PATH, true)); + ${KEEPPREFSIZE} + } + + /** This method is called from within the constructor to + * initialize the form. + * WARNING: Do NOT modify this code. The content of this method is + * always regenerated by the Form Editor. + */ + // //GEN-BEGIN:initComponents + private void initComponents() { + + org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(this); + this.setLayout(layout); + layout.setHorizontalGroup( + layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 400, Short.MAX_VALUE) + ); + layout.setVerticalGroup( + layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING) + .add(0, 300, Short.MAX_VALUE) + ); + }// //GEN-END:initComponents + + + // Variables declaration - do not modify//GEN-BEGIN:variables + // End of variables declaration//GEN-END:variables + + /** + * Gets default instance. Do not use directly: reserved for *.settings files only, + * i.e. deserialization routines; otherwise you could get a non-deserialized instance. + * To obtain the singleton instance, use {@link #findInstance}. + */ + public static synchronized ${TEMPLATENAME}TopComponent getDefault() { + if (instance == null) { + instance = new ${TEMPLATENAME}TopComponent(); + } + return instance; + } + + /** + * Obtain the ${TEMPLATENAME}TopComponent instance. Never call {@link #getDefault} directly! + */ + public static synchronized ${TEMPLATENAME}TopComponent findInstance() { + TopComponent win = WindowManager.getDefault().findTopComponent(PREFERRED_ID); + if (win == null) { + Logger.getLogger(${TEMPLATENAME}TopComponent.class.getName()).warning( + "Cannot find " + PREFERRED_ID + " component. It will not be located properly in the window system."); + return getDefault(); + } + if (win instanceof ${TEMPLATENAME}TopComponent) { + return (${TEMPLATENAME}TopComponent)win; + } + Logger.getLogger(${TEMPLATENAME}TopComponent.class.getName()).warning( + "There seem to be multiple components with the '" + PREFERRED_ID + + "' ID. That is a potential source of errors and unexpected behavior."); + return getDefault(); + } + + @Override + public int getPersistenceType() { + return TopComponent.PERSISTENCE_ALWAYS; + } + + @Override + public void componentOpened() { + // TODO add custom code on component opening + } + + @Override + public void componentClosed() { + // TODO add custom code on component closing + } + + void writeProperties(java.util.Properties p) { + // better to version settings since initial version as advocated at + // http://wiki.apidesign.org/wiki/PropertyFiles + p.setProperty("version", "1.0"); + // TODO store your settings + } + Object readProperties(java.util.Properties p) { + ${TEMPLATENAME}TopComponent singleton = ${TEMPLATENAME}TopComponent.getDefault(); + singleton.readPropertiesImpl(p); + return singleton; + } + + private void readPropertiesImpl(java.util.Properties p) { + String version = p.getProperty("version"); + // TODO read your settings according to their version + } + + @Override + protected String preferredID() { + return PREFERRED_ID; + } +} diff --git a/core.startup/src/org/netbeans/core/startup/NbInstaller.java b/core.startup/src/org/netbeans/core/startup/NbInstaller.java --- a/core.startup/src/org/netbeans/core/startup/NbInstaller.java +++ b/core.startup/src/org/netbeans/core/startup/NbInstaller.java @@ -49,11 +49,13 @@ import java.net.URL; import java.nio.ByteBuffer; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Locale; @@ -543,20 +545,20 @@ // #23609: dependent modules should be able to override: modules = new ArrayList(modules); Collections.reverse(modules); - Map> urls = new HashMap>(5); + Map> urls = new HashMap>(5); ModuleLayeredFileSystem userModuleLayer = ModuleLayeredFileSystem.getUserModuleLayer(); ModuleLayeredFileSystem installationModuleLayer = ModuleLayeredFileSystem.getInstallationModuleLayer(); - urls.put(userModuleLayer, new ArrayList(1000)); - urls.put(installationModuleLayer, new ArrayList(1000)); + urls.put(userModuleLayer, new LinkedHashSet(1000)); + urls.put(installationModuleLayer, new LinkedHashSet(1000)); for (Module m: modules) { // #19458: only put reloadables into the "session layer" // (where they will not have their layers cached). All others // should go into "installation layer" (so that they can mask // layers according to cross-dependencies). ModuleLayeredFileSystem host = m.isReloadable() ? userModuleLayer : installationModuleLayer; - List theseurls = urls.get(host); + Collection theseurls = urls.get(host); if (theseurls == null) { - theseurls = new ArrayList(1000); + theseurls = new LinkedHashSet(1000); urls.put(host, theseurls); } ClassLoader cl = m.getClassLoader(); @@ -595,16 +597,17 @@ findResources.setAccessible(true); Enumeration e = (Enumeration) findResources.invoke(cl, "META-INF/generated-layer.xml"); // NOI18N while (e.hasMoreElements()) { - theseurls.add((URL) e.nextElement()); + URL u = (URL)e.nextElement(); + theseurls.add(u); } } catch (Exception x) { Exceptions.printStackTrace(x); } } // Now actually do it. - for (Map.Entry> entry: urls.entrySet()) { + for (Map.Entry> entry: urls.entrySet()) { ModuleLayeredFileSystem host = entry.getKey(); - List theseurls = entry.getValue(); + Collection theseurls = entry.getValue(); Util.err.fine("Adding/removing layer URLs: host=" + host + " urls=" + theseurls); try { if (load) { diff --git a/settings/api/doc/org/netbeans/api/settings/package.html b/settings/api/doc/org/netbeans/api/settings/package.html new file mode 100644 --- /dev/null +++ b/settings/api/doc/org/netbeans/api/settings/package.html @@ -0,0 +1,53 @@ + + + + + + + org.netbeans.api.settings package + + + This package provides annotations to simplify use of + convertors. + + diff --git a/settings/api/doc/org/netbeans/spi/settings/doc-files/api.html b/settings/api/doc/org/netbeans/spi/settings/doc-files/api.html --- a/settings/api/doc/org/netbeans/spi/settings/doc-files/api.html +++ b/settings/api/doc/org/netbeans/spi/settings/doc-files/api.html @@ -183,7 +183,7 @@ To create a persistent instance use method - + org.openide.loaders.InstanceDataObject.create. The framework will look up the provider registration for the exact class of the object passed into the method. @@ -331,8 +331,10 @@
 <ANY-ACCESS-MODIFIER> void writeProperties(java.util.Properties p)
 
- -It is the setting object concern to collect all properties of its super classes. +It is the setting object concern to collect all properties of its super classes. +Since version 1.18, the readProperties can also return an Object. +In such case, the XMLPropertiesConvertor replaces the current object +with the returned one.

The XMLProperties convertor also makes possible to prevent automatic storing of the setting object by using file attribute xmlproperties.preventStoring diff --git a/settings/apichanges.xml b/settings/apichanges.xml --- a/settings/apichanges.xml +++ b/settings/apichanges.xml @@ -105,6 +105,20 @@ + + +

@ConvertAsProperties annotation + + + + + + Human friendly way to register XML property based convertor via + the @ConvertAsProperties annotation. + + + + Allow convertors to recognize .xml files in specially attributed folders. diff --git a/settings/nbproject/project.properties b/settings/nbproject/project.properties --- a/settings/nbproject/project.properties +++ b/settings/nbproject/project.properties @@ -46,4 +46,4 @@ javadoc.main.page=org/netbeans/spi/settings/doc-files/api.html # Extra classpath used to run unit tests #test.unit.cp.extra=${core.dir}/core/core.jar:${core.dir}/lib/boot.jar:${core.dir}/core/core.jar -spec.version.base=1.17.0 +spec.version.base=1.18.0 diff --git a/settings/nbproject/project.xml b/settings/nbproject/project.xml --- a/settings/nbproject/project.xml +++ b/settings/nbproject/project.xml @@ -156,6 +156,7 @@ + org.netbeans.api.settings org.netbeans.spi.settings diff --git a/settings/src/org/netbeans/api/settings/ConvertAsProperties.java b/settings/src/org/netbeans/api/settings/ConvertAsProperties.java new file mode 100644 --- /dev/null +++ b/settings/src/org/netbeans/api/settings/ConvertAsProperties.java @@ -0,0 +1,47 @@ + +package org.netbeans.api.settings; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.util.Properties; + +/** Annotation to attach to object that is wishing to support conversion from + * and to {@link Properties}. More info about the format and protocol + * is available in separate document, + * here is the shortest possible howto: + *
+ * @ConvertAsProperties(dtd="-//Your Org//Your Setting//EN")
+ * public class YourObject {
+ *   public YourObject() {} // public constructor is a must
+ *   void readProperties(java.util.Properties p) {
+ *     // do the read
+ *   }
+ *   void writeProperties(java.util.Properties p) {
+ *     // handle the store
+ *   }
+ * }
+ * 
+ * + * @author Jaroslav Tulach + * @since 1.18 + */ +@Retention(RetentionPolicy.SOURCE) +@Target(ElementType.TYPE) +public @interface ConvertAsProperties { + /** Public ID of the XML file that results in creation of the + * annotated type and to which the annotated type can be converted. + * @return public ID of the file's DTD + */ + String dtd(); + /** Shall every change in the object result in save? Or shall the + * object just be marked as dirty? + */ + boolean autostore() default true; + /** An array of properties that are ignored without marking the object + * as dirty or saving it. + * @return array of property names or "all" to ignore all properties + */ + String[] ignoreChanges() default {}; +} diff --git a/settings/src/org/netbeans/modules/settings/convertors/ConvertorProcessor.java b/settings/src/org/netbeans/modules/settings/convertors/ConvertorProcessor.java new file mode 100644 --- /dev/null +++ b/settings/src/org/netbeans/modules/settings/convertors/ConvertorProcessor.java @@ -0,0 +1,246 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ + +package org.netbeans.modules.settings.convertors; + +import java.util.Set; +import javax.annotation.processing.Processor; +import javax.annotation.processing.RoundEnvironment; +import javax.annotation.processing.SupportedAnnotationTypes; +import javax.annotation.processing.SupportedSourceVersion; +import javax.lang.model.SourceVersion; +import javax.lang.model.element.Element; +import javax.lang.model.element.ExecutableElement; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.ElementFilter; +import org.netbeans.api.settings.ConvertAsProperties; +import org.openide.filesystems.annotations.LayerBuilder.File; +import org.openide.filesystems.annotations.LayerGeneratingProcessor; +import org.openide.filesystems.annotations.LayerGenerationException; +import org.openide.util.lookup.ServiceProvider; + +/** Processor to hide all the complexities of settings layer registration. + * + * @author Jaroslav Tulach + */ +@ServiceProvider(service=Processor.class) +@SupportedSourceVersion(SourceVersion.RELEASE_6) +@SupportedAnnotationTypes("org.netbeans.api.settings.ConvertAsProperties")//NOI18N +public class ConvertorProcessor extends LayerGeneratingProcessor { + + + @Override + protected boolean handleProcess( + Set annotations, + RoundEnvironment env + ) throws LayerGenerationException { + for (Element e : env.getElementsAnnotatedWith(ConvertAsProperties.class)) { + ConvertAsProperties reg = e.getAnnotation(ConvertAsProperties.class); + + String[] convElem = instantiableClassOrMethod(e, null); + final String dtd = reg.dtd(); + + String dtdCode = convertPublicId(dtd); + + /* + + + + + + */ + layer(e).file("xml/entities" + dtdCode). + url("nbres:/org/netbeans/modules/settings/resources/properties-1_0.dtd"). + stringvalue("hint.originalPublicID", dtd).write(); + /* + + + + + + + + + */ + layer(e).file("xml/memory/" + convElem[0].replace('.', '/')). + stringvalue("settings.providerPath", "xml/lookups/" + dtdCode + ".instance"). + write(); + + /* + + + + + + + + + + */ + File f = layer(e).file("xml/lookups" + dtdCode + ".instance"). + methodvalue("instanceCreate", "org.netbeans.api.settings.Factory", "create"). + methodvalue("settings.convertor", "org.netbeans.api.settings.Factory", "properties"). + stringvalue("settings.instanceClass", convElem[0]). + stringvalue("settings.instanceOf", convElem[0]). + boolvalue("xmlproperties.preventStoring", !reg.autostore()); + commaSeparated(f, reg.ignoreChanges()).write(); + } + return false; + } + + /** Copied from FileEntityResolver from o.n.core module. + */ + @SuppressWarnings("fallthrough") + private static String convertPublicId (String publicID) { + char[] arr = publicID.toCharArray (); + + + int numberofslashes = 0; + int state = 0; + int write = 0; + OUT: for (int i = 0; i < arr.length; i++) { + char ch = arr[i]; + + switch (state) { + case 0: + // initial state + if (ch == '+' || ch == '-' || ch == 'I' || ch == 'S' || ch == 'O') { + // do not write that char + continue; + } + // switch to regular state + state = 1; + // fallthru + case 1: + // regular state expecting any character + if (ch == '/') { + state = 2; + if (++numberofslashes == 3) { + // last part of the ID, exit + break OUT; + } + arr[write++] = '/'; + continue; + } + break; + case 2: + // previous character was / + if (ch == '/') { + // ignore second / and write nothing + continue; + } + state = 1; + break; + } + + // write the char into the array + if (ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z' || ch >= '0' && ch <= '9') { + arr[write++] = ch; + } else { + arr[write++] = '_'; + } + } + + return new String (arr, 0, write); + } + + private static File commaSeparated(File f, String[] arr) { + if (arr.length == 0) { + return f; + } + + StringBuilder sb = new StringBuilder(); + String sep = ""; + for (String s : arr) { + sb.append(sep); + sb.append(s); + sep = ","; + } + return f.stringvalue("xmlproperties.ignoreChanges", sb.toString()); + } + + private String[] instantiableClassOrMethod(Element e, Class type) throws IllegalArgumentException, LayerGenerationException { + TypeMirror typeMirror = type != null ? processingEnv.getElementUtils().getTypeElement(type.getName().replace('$', '.')).asType() : null; + switch (e.getKind()) { + case CLASS: { + String clazz = processingEnv.getElementUtils().getBinaryName((TypeElement) e).toString(); + if (e.getModifiers().contains(Modifier.ABSTRACT)) { + throw new LayerGenerationException(clazz + " must not be abstract", e); + } + { + boolean hasDefaultCtor = false; + for (ExecutableElement constructor : ElementFilter.constructorsIn(e.getEnclosedElements())) { + if (constructor.getParameters().isEmpty()) { + hasDefaultCtor = true; + break; + } + } + if (!hasDefaultCtor) { + throw new LayerGenerationException(clazz + " must have a no-argument constructor", e); + } + } + if (typeMirror != null && !processingEnv.getTypeUtils().isAssignable(e.asType(), typeMirror)) { + throw new LayerGenerationException(clazz + " is not assignable to " + typeMirror, e); + } + return new String[] {clazz, null}; + } + case METHOD: { + String clazz = processingEnv.getElementUtils().getBinaryName((TypeElement) e.getEnclosingElement()).toString(); + String method = e.getSimpleName().toString(); + if (!e.getModifiers().contains(Modifier.STATIC)) { + throw new LayerGenerationException(clazz + "." + method + " must be static", e); + } + if (!((ExecutableElement) e).getParameters().isEmpty()) { + throw new LayerGenerationException(clazz + "." + method + " must not take arguments", e); + } + if (typeMirror != null && !processingEnv.getTypeUtils().isAssignable(((ExecutableElement) e).getReturnType(), typeMirror)) { + throw new LayerGenerationException(clazz + "." + method + " is not assignable to " + typeMirror, e); + } + return new String[] {clazz, method}; + } + default: + throw new IllegalArgumentException("Annotated element is not loadable as an instance: " + e); + } + } +} diff --git a/settings/src/org/netbeans/modules/settings/convertors/XMLPropertiesConvertor.java b/settings/src/org/netbeans/modules/settings/convertors/XMLPropertiesConvertor.java --- a/settings/src/org/netbeans/modules/settings/convertors/XMLPropertiesConvertor.java +++ b/settings/src/org/netbeans/modules/settings/convertors/XMLPropertiesConvertor.java @@ -93,8 +93,7 @@ public Object read(java.io.Reader r) throws IOException, ClassNotFoundException { Object def = defaultInstanceCreate(); - readSetting(r, def); - return def; + return readSetting(r, def); } public void write(java.io.Writer w, Object inst) throws IOException { @@ -243,7 +242,7 @@ return ((ClassLoader)Lookup.getDefault().lookup(ClassLoader.class)).loadClass(instanceClass); } - private void readSetting(java.io.Reader input, Object inst) throws IOException { + private Object readSetting(java.io.Reader input, Object inst) throws IOException { try { java.lang.reflect.Method m = inst.getClass().getDeclaredMethod( "readProperties", new Class[] {Properties.class}); // NOI18N @@ -251,7 +250,11 @@ XMLPropertiesConvertor.Reader r = new XMLPropertiesConvertor.Reader(); r.parse(input); m.setAccessible(true); - m.invoke(inst, new Object[] {r.getProperties()}); + Object ret = m.invoke(inst, new Object[] {r.getProperties()}); + if (ret == null) { + ret = inst; + } + return ret; } catch (NoSuchMethodException ex) { IOException ioe = new IOException(ex.getMessage()); ioe.initCause(ex); diff --git a/settings/test/unit/src/org/netbeans/modules/settings/convertors/XMLPropertiesConvertorAnnotationTest.java b/settings/test/unit/src/org/netbeans/modules/settings/convertors/XMLPropertiesConvertorAnnotationTest.java new file mode 100644 --- /dev/null +++ b/settings/test/unit/src/org/netbeans/modules/settings/convertors/XMLPropertiesConvertorAnnotationTest.java @@ -0,0 +1,98 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this + * particular file as subject to the "Classpath" exception as provided + * by Sun in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * Contributor(s): + * + * The Original Software is NetBeans. The Initial Developer of the Original + * Software is Sun Microsystems, Inc. Portions Copyright 2002 Sun + * Microsystems, Inc. All Rights Reserved. + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + */ + +package org.netbeans.modules.settings.convertors; + +import java.io.*; + +import java.util.Properties; +import org.netbeans.junit.NbTestCase; + + +import org.netbeans.api.settings.ConvertAsProperties; +import org.netbeans.spi.settings.Convertor; + +import org.openide.filesystems.FileObject; +import org.openide.filesystems.Repository; + +/** Checks usage of annotation to assign XML properties convertor. + * + * @author Jaroslav Tulach + */ +public final class XMLPropertiesConvertorAnnotationTest extends NbTestCase { + /** Creates a new instance of XMLPropertiesConvertorTest */ + public XMLPropertiesConvertorAnnotationTest(String name) { + super(name); + } + + public void testReadWrite() throws Exception { + FileObject dtdFO = Repository.getDefault().getDefaultFileSystem(). + findResource("/xml/lookups/NetBeans_org_netbeans_modules_settings_xtest/DTD_XML_FooSetting_2_0.instance"); + assertNotNull("Provider not found", dtdFO); + Convertor c = XMLPropertiesConvertor.create(dtdFO); + AnnoFoo foo = new AnnoFoo(); + foo.setProperty1("xxx"); + CharArrayWriter caw = new CharArrayWriter(1024); + c.write(caw, foo); + caw.flush(); + caw.close(); + CharArrayReader car = new CharArrayReader(caw.toCharArray()); + Object obj = c.read(car); + assertEquals(foo, obj); + assertEquals("HooFoo is the class", HooFoo.class, obj.getClass()); + } + + @ConvertAsProperties( + dtd="-//NetBeans org.netbeans.modules.settings.xtest//DTD XML FooSetting 2.0//EN" + ) + public static class AnnoFoo extends FooSetting { + public Object readProperties(Properties p) { + HooFoo n = new HooFoo(); + n.setProperty1(p.getProperty("p1")); + return n; + } + public void writeProperties(Properties p) { + p.setProperty("p1", this.getProperty1()); + } + } + public static class HooFoo extends AnnoFoo { + } +} diff --git a/settings/test/unit/src/org/netbeans/modules/settings/convertors/XMLPropertiesConvertorTest.java b/settings/test/unit/src/org/netbeans/modules/settings/convertors/XMLPropertiesConvertorTest.java --- a/settings/test/unit/src/org/netbeans/modules/settings/convertors/XMLPropertiesConvertorTest.java +++ b/settings/test/unit/src/org/netbeans/modules/settings/convertors/XMLPropertiesConvertorTest.java @@ -44,15 +44,11 @@ import java.io.*; import org.netbeans.junit.NbTestCase; -import org.netbeans.junit.NbTestSuite; -import junit.textui.TestRunner; -import org.netbeans.modules.settings.convertors.FooSetting; import org.netbeans.spi.settings.Convertor; import org.netbeans.spi.settings.Saver; import org.openide.cookies.InstanceCookie; -import org.openide.cookies.SaveCookie; import org.openide.filesystems.FileLock; import org.openide.filesystems.FileObject;