();
@@ -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 extends TypeElement> 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());
+ }
+ }
+}