diff -r b3bbc4d76b98 -r 99f9487ce5d5 .hgtags --- a/.hgtags Sat Dec 20 13:17:51 2008 +0100 +++ b/.hgtags Wed Jan 07 10:33:13 2009 +0100 @@ -903,3 +903,4 @@ 97a25b3dd3d6aa7c9b780a84c570525509ada018 release65_beta_base f4e13fba708a8a4de40b8970ef8381abfc4314a0 release65_base 70566ac355c30cde654cd268b429bc22f8e13240 release70_m1_base +b3bbc4d76b98f3a02b5bfc91b0de5e10e52ea2fa convertAsProperties_155962_base diff -r b3bbc4d76b98 -r 99f9487ce5d5 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 Sat Dec 20 13:17:51 2008 +0100 +++ b/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/resources/layer.xml Wed Jan 07 10:33:13 2009 +0100 @@ -229,6 +229,7 @@ + diff -r b3bbc4d76b98 -r 99f9487ce5d5 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 Sat Dec 20 13:17:51 2008 +0100 +++ b/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/wizard/winsys/NewTCIterator.java Wed Jan 07 10:33:13 2009 +0100 @@ -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 -r b3bbc4d76b98 -r 99f9487ce5d5 apisupport.project/src/org/netbeans/modules/apisupport/project/ui/wizard/winsys/templateTopComponentAnno.javx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/wizard/winsys/templateTopComponentAnno.javx Wed Jan 07 10:33:13 2009 +0100 @@ -0,0 +1,129 @@ +<#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.ImageUtilities; +import org.netbeans.api.settings.ConvertAsProperties; + +/** + * Top component which displays something. + */ +@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(ImageUtilities.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 -r b3bbc4d76b98 -r 99f9487ce5d5 settings/api/doc/org/netbeans/api/settings/package.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/settings/api/doc/org/netbeans/api/settings/package.html Wed Jan 07 10:33:13 2009 +0100 @@ -0,0 +1,53 @@ + + + + + + + org.netbeans.api.settings package + + + This package provides annotations to simplify use of + convertors. + + diff -r b3bbc4d76b98 -r 99f9487ce5d5 settings/api/doc/org/netbeans/spi/settings/doc-files/api.html --- a/settings/api/doc/org/netbeans/spi/settings/doc-files/api.html Sat Dec 20 13:17:51 2008 +0100 +++ b/settings/api/doc/org/netbeans/spi/settings/doc-files/api.html Wed Jan 07 10:33:13 2009 +0100 @@ -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 -r b3bbc4d76b98 -r 99f9487ce5d5 settings/apichanges.xml --- a/settings/apichanges.xml Sat Dec 20 13:17:51 2008 +0100 +++ b/settings/apichanges.xml Wed Jan 07 10:33:13 2009 +0100 @@ -105,6 +105,34 @@ + + +

readProperties can designate its replace + + + + + + Semantics of readProperties method has been extended + to allow the method to return an object. Read + more. + + + + + + @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 -r b3bbc4d76b98 -r 99f9487ce5d5 settings/nbproject/project.properties --- a/settings/nbproject/project.properties Sat Dec 20 13:17:51 2008 +0100 +++ b/settings/nbproject/project.properties Wed Jan 07 10:33:13 2009 +0100 @@ -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 -r b3bbc4d76b98 -r 99f9487ce5d5 settings/nbproject/project.xml --- a/settings/nbproject/project.xml Sat Dec 20 13:17:51 2008 +0100 +++ b/settings/nbproject/project.xml Wed Jan 07 10:33:13 2009 +0100 @@ -156,6 +156,7 @@ + org.netbeans.api.settings org.netbeans.spi.settings diff -r b3bbc4d76b98 -r 99f9487ce5d5 settings/src/org/netbeans/api/settings/ConvertAsProperties.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/settings/src/org/netbeans/api/settings/ConvertAsProperties.java Wed Jan 07 10:33:13 2009 +0100 @@ -0,0 +1,52 @@ + +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 { + /** constant to return from {@link #ignoreChanges()} to signal that all + * property changes shall be ignored. + */ + public static final String IGNORE_ALL_CHANGES = "all"; + + /** 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 {@link #IGNORE_ALL_CHANGES} to ignore all properties + */ + String[] ignoreChanges() default {}; +} diff -r b3bbc4d76b98 -r 99f9487ce5d5 settings/src/org/netbeans/modules/settings/convertors/ConvertorProcessor.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/settings/src/org/netbeans/modules/settings/convertors/ConvertorProcessor.java Wed Jan 07 10:33:13 2009 +0100 @@ -0,0 +1,262 @@ +/* + * 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.TypeKind; +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 { + if (env.processingOver()) { + return false; + } + + for (Element e : env.getElementsAnnotatedWith(ConvertAsProperties.class)) { + ConvertAsProperties reg = e.getAnnotation(ConvertAsProperties.class); + + String convElem = instantiableClassOrMethod(e); + 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.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). + stringvalue("settings.instanceOf", convElem). + 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) throws IllegalArgumentException, LayerGenerationException { + 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); + } + } + TypeMirror propType; + propType = processingEnv.getElementUtils().getTypeElement("java.util.Properties").asType(); + { + boolean hasRead = false; + boolean hasWrite = false; + for (ExecutableElement m : ElementFilter.methodsIn(e.getEnclosedElements())) { + if ( + m.getParameters().size() == 1 && + m.getSimpleName().contentEquals("readProperties") && + m.getParameters().get(0).asType().equals(propType) + ) { + hasRead = true; + } + if ( + m.getParameters().size() == 1 && + m.getSimpleName().contentEquals("writeProperties") && + m.getParameters().get(0).asType().equals(propType) && + m.getReturnType().getKind() == TypeKind.VOID + ) { + hasWrite = true; + } + } + if (!hasRead) { + throw new LayerGenerationException(clazz + " must have proper readProperties method", e); + } + if (!hasWrite) { + throw new LayerGenerationException(clazz + " must have proper writeProperties method", e); + } + } + return clazz; + } + default: + throw new IllegalArgumentException("Annotated element is not loadable as an instance: " + e); + } + } +} diff -r b3bbc4d76b98 -r 99f9487ce5d5 settings/src/org/netbeans/modules/settings/convertors/XMLPropertiesConvertor.java --- a/settings/src/org/netbeans/modules/settings/convertors/XMLPropertiesConvertor.java Sat Dec 20 13:17:51 2008 +0100 +++ b/settings/src/org/netbeans/modules/settings/convertors/XMLPropertiesConvertor.java Wed Jan 07 10:33:13 2009 +0100 @@ -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); @@ -317,6 +320,7 @@ private Properties props = new Properties(); private String publicId; + @Override public org.xml.sax.InputSource resolveEntity(String publicId, String systemId) throws SAXException { if (this.publicId != null && this.publicId.equals (publicId)) { @@ -326,6 +330,7 @@ } } + @Override public void startElement(String uri, String localName, String qName, org.xml.sax.Attributes attribs) throws SAXException { if (ELM_PROPERTY.equals(qName)) { String propertyName = attribs.getValue(ATR_PROPERTY_NAME); diff -r b3bbc4d76b98 -r 99f9487ce5d5 settings/test/unit/src/org/netbeans/modules/settings/convertors/XMLPropertiesConvertorAnnotationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/settings/test/unit/src/org/netbeans/modules/settings/convertors/XMLPropertiesConvertorAnnotationTest.java Wed Jan 07 10:33:13 2009 +0100 @@ -0,0 +1,169 @@ +/* + * 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; +import org.openide.util.test.AnnotationProcessorTestUtils; + +/** 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); + } + + @Override + protected void setUp() throws Exception { + clearWorkDir(); + } + + 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 { + } + + public void testVerifyHaveDefaultConstructor() throws Exception { + AnnotationProcessorTestUtils.makeSource(getWorkDir(), "x.y.Kuk", + "import org.netbeans.api.settings.ConvertAsProperties;\n" + + "@ConvertAsProperties(dtd=\"-//x.y//Kuk//EN\")\n" + + "public class Kuk {\n" + + " public Kuk(int i) {}\n" + + "}\n" + ); + ByteArrayOutputStream err = new ByteArrayOutputStream(); + boolean res = AnnotationProcessorTestUtils.runJavac(getWorkDir(), null, getWorkDir(), null, err); + assertFalse("Should fail", res); + if (err.toString().indexOf("x.y.Kuk must have a no-argument constructor") == -1) { + fail("Wrong error message:\n" + err.toString()); + } + } + public void testVerifyReadProperties() throws Exception { + AnnotationProcessorTestUtils.makeSource(getWorkDir(), "x.y.Kuk", + "import org.netbeans.api.settings.ConvertAsProperties;\n" + + "@ConvertAsProperties(dtd=\"-//x.y//Kuk//EN\")\n" + + "public class Kuk {\n" + + " public Kuk() {}\n" + + " public void writeProperties(java.util.Properties p){}\n" + + "}\n" + ); + ByteArrayOutputStream err = new ByteArrayOutputStream(); + boolean res = AnnotationProcessorTestUtils.runJavac(getWorkDir(), null, getWorkDir(), null, err); + assertFalse("Should fail", res); + if (err.toString().indexOf("x.y.Kuk must have proper readProperties method") == -1) { + fail("Wrong error message:\n" + err.toString()); + } + } + public void testVerifyWriteProperties() throws Exception { + AnnotationProcessorTestUtils.makeSource(getWorkDir(), "x.y.Kuk", + "import org.netbeans.api.settings.ConvertAsProperties;\n" + + "@ConvertAsProperties(dtd=\"-//x.y//Kuk//EN\")\n" + + "public class Kuk {\n" + + " public Kuk() {}\n" + + " public void readProperties(java.util.Properties p){}\n" + + "}\n" + ); + ByteArrayOutputStream err = new ByteArrayOutputStream(); + boolean res = AnnotationProcessorTestUtils.runJavac(getWorkDir(), null, getWorkDir(), null, err); + assertFalse("Should fail", res); + if (err.toString().indexOf("x.y.Kuk must have proper writeProperties method") == -1) { + fail("Wrong error message:\n" + err.toString()); + } + } + public void testVerifyWritePropertiesReturnsVoid() throws Exception { + AnnotationProcessorTestUtils.makeSource(getWorkDir(), "x.y.Kuk", + "import org.netbeans.api.settings.ConvertAsProperties;\n" + + "@ConvertAsProperties(dtd=\"-//x.y//Kuk//EN\")\n" + + "public class Kuk {\n" + + " public Kuk() {}\n" + + " public void readProperties(java.util.Properties p){}\n" + + " public int writeProperties(java.util.Properties p){}\n" + + "}\n" + ); + ByteArrayOutputStream err = new ByteArrayOutputStream(); + boolean res = AnnotationProcessorTestUtils.runJavac(getWorkDir(), null, getWorkDir(), null, err); + assertFalse("Should fail", res); + if (err.toString().indexOf("x.y.Kuk must have proper writeProperties method") == -1) { + fail("Wrong error message:\n" + err.toString()); + } + } +}