This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 155962
Collapse All | Expand All

(-)a/.hgtags (+1 lines)
Lines 903-905 Link Here
903
97a25b3dd3d6aa7c9b780a84c570525509ada018 release65_beta_base
903
97a25b3dd3d6aa7c9b780a84c570525509ada018 release65_beta_base
904
f4e13fba708a8a4de40b8970ef8381abfc4314a0 release65_base
904
f4e13fba708a8a4de40b8970ef8381abfc4314a0 release65_base
905
70566ac355c30cde654cd268b429bc22f8e13240 release70_m1_base
905
70566ac355c30cde654cd268b429bc22f8e13240 release70_m1_base
906
b3bbc4d76b98f3a02b5bfc91b0de5e10e52ea2fa convertAsProperties_155962_base
(-)a/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/resources/layer.xml (+1 lines)
Lines 229-234 Link Here
229
            <file name="templateSettings.xml" url="../wizard/winsys/templateSettings.xml"/>
229
            <file name="templateSettings.xml" url="../wizard/winsys/templateSettings.xml"/>
230
            <file name="templateTopComponent.form" url="../wizard/winsys/templateTopComponent.frmx"/>
230
            <file name="templateTopComponent.form" url="../wizard/winsys/templateTopComponent.frmx"/>
231
            <file name="templateTopComponent.java" url="../wizard/winsys/templateTopComponent.javx"/>
231
            <file name="templateTopComponent.java" url="../wizard/winsys/templateTopComponent.javx"/>
232
            <file name="templateTopComponentAnno.java" url="../wizard/winsys/templateTopComponentAnno.javx"/>
232
            <file name="templateWstcref.xml" url="../wizard/winsys/templateWstcref.xml"/>
233
            <file name="templateWstcref.xml" url="../wizard/winsys/templateWstcref.xml"/>
233
            <file name="instantiatingIterator.java" url="../wizard/wizard/instantiatingIterator.javx"/>
234
            <file name="instantiatingIterator.java" url="../wizard/wizard/instantiatingIterator.javx"/>
234
            <file name="sampleAction.java" url="../wizard/wizard/sampleAction.javx"/>
235
            <file name="sampleAction.java" url="../wizard/wizard/sampleAction.javx"/>
(-)a/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/wizard/winsys/NewTCIterator.java (-1 / +14 lines)
Lines 185-190 Link Here
185
            Logger.getLogger(NewTCIterator.class.getName()).log(Level.INFO, null, ex);
185
            Logger.getLogger(NewTCIterator.class.getName()).log(Level.INFO, null, ex);
186
            actionLessTC = false;
186
            actionLessTC = false;
187
        }
187
        }
188
        boolean propertiesPersistence;
189
        try {
190
            SpecificationVersion current = model.getModuleInfo().getDependencyVersion("org.netbeans.modules.settings");
191
            propertiesPersistence = current.compareTo(new SpecificationVersion("1.18")) >= 0; // NOI18N
192
        } catch (IOException ex) {
193
            Logger.getLogger(NewTCIterator.class.getName()).log(Level.INFO, null, ex);
194
            propertiesPersistence = false;
195
        }
188
196
189
        
197
        
190
        Map<String,String> replaceTokens = new HashMap<String,String>();
198
        Map<String,String> replaceTokens = new HashMap<String,String>();
Lines 233-243 Link Here
233
        fileChanges.add(fileChanges.addModuleDependency("org.openide.util")); //NOI18N
241
        fileChanges.add(fileChanges.addModuleDependency("org.openide.util")); //NOI18N
234
        fileChanges.add(fileChanges.addModuleDependency("org.openide.awt")); //NOI18N
242
        fileChanges.add(fileChanges.addModuleDependency("org.openide.awt")); //NOI18N
235
        fileChanges.add(fileChanges.addModuleDependency("org.jdesktop.layout")); //NOI18N
243
        fileChanges.add(fileChanges.addModuleDependency("org.jdesktop.layout")); //NOI18N
244
        if (propertiesPersistence) {
245
            fileChanges.add(fileChanges.addModuleDependency("org.netbeans.modules.settings")); //NOI18N
246
        }
236
        
247
        
237
        // x. generate java classes
248
        // x. generate java classes
238
        final String tcName = getRelativePath(moduleInfo.getSourceDirectoryPath(), packageName,
249
        final String tcName = getRelativePath(moduleInfo.getSourceDirectoryPath(), packageName,
239
                name, "TopComponent.java"); //NOI18N
250
                name, "TopComponent.java"); //NOI18N
240
        FileObject template = CreatedModifiedFiles.getTemplate("templateTopComponent.java");//NOI18N
251
        FileObject template = CreatedModifiedFiles.getTemplate(
252
            propertiesPersistence ? "templateTopComponentAnno.java" : "templateTopComponent.java" //NOI18N
253
        );
241
        fileChanges.add(fileChanges.createFileWithSubstitutions(tcName, template, replaceTokens));
254
        fileChanges.add(fileChanges.createFileWithSubstitutions(tcName, template, replaceTokens));
242
        // x. generate java classes
255
        // x. generate java classes
243
        final String tcFormName = getRelativePath(moduleInfo.getSourceDirectoryPath(), packageName,
256
        final String tcFormName = getRelativePath(moduleInfo.getSourceDirectoryPath(), packageName,
(-)b3bbc4d76b98 (+129 lines)
Added Link Here
1
<#assign licenseFirst = "/*">
2
<#assign licensePrefix = " * ">
3
<#assign licenseLast = " */">
4
<#include "../Licenses/license-${project.license}.txt">
5
6
package ${PACKAGENAME};
7
8
import java.util.logging.Logger;
9
import org.openide.util.NbBundle;
10
import org.openide.windows.TopComponent;
11
import org.openide.windows.WindowManager;
12
${COMMENTICON}import org.openide.util.ImageUtilities;
13
import org.netbeans.api.settings.ConvertAsProperties;
14
15
/**
16
 * Top component which displays something.
17
 */
18
@ConvertAsProperties(
19
    dtd="-//${PACKAGENAME}//${TEMPLATENAME}//EN",
20
    autostore=false
21
)
22
public final class ${TEMPLATENAME}TopComponent extends TopComponent {
23
24
    private static ${TEMPLATENAME}TopComponent instance;
25
    /** path to the icon used by the component and its open action */
26
${COMMENTICON}    static final String ICON_PATH = "${ICONPATH}";
27
28
    private static final String PREFERRED_ID = "${TEMPLATENAME}TopComponent";
29
30
    public ${TEMPLATENAME}TopComponent() {
31
        initComponents();
32
        setName(NbBundle.getMessage(${TEMPLATENAME}TopComponent.class, "CTL_${TEMPLATENAME}TopComponent"));
33
        setToolTipText(NbBundle.getMessage(${TEMPLATENAME}TopComponent.class, "HINT_${TEMPLATENAME}TopComponent"));
34
${COMMENTICON}        setIcon(ImageUtilities.loadImage(ICON_PATH, true));
35
        ${KEEPPREFSIZE}
36
    }
37
38
    /** This method is called from within the constructor to
39
     * initialize the form.
40
     * WARNING: Do NOT modify this code. The content of this method is
41
     * always regenerated by the Form Editor.
42
     */
43
    // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
44
    private void initComponents() {
45
46
        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(this);
47
        this.setLayout(layout);
48
        layout.setHorizontalGroup(
49
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
50
            .add(0, 400, Short.MAX_VALUE)
51
        );
52
        layout.setVerticalGroup(
53
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
54
            .add(0, 300, Short.MAX_VALUE)
55
        );
56
    }// </editor-fold>//GEN-END:initComponents
57
58
59
    // Variables declaration - do not modify//GEN-BEGIN:variables
60
    // End of variables declaration//GEN-END:variables
61
62
    /**
63
     * Gets default instance. Do not use directly: reserved for *.settings files only,
64
     * i.e. deserialization routines; otherwise you could get a non-deserialized instance.
65
     * To obtain the singleton instance, use {@link #findInstance}.
66
     */
67
    public static synchronized ${TEMPLATENAME}TopComponent getDefault() {
68
        if (instance == null) {
69
            instance = new ${TEMPLATENAME}TopComponent();
70
        }
71
        return instance;
72
    }
73
74
    /**
75
     * Obtain the ${TEMPLATENAME}TopComponent instance. Never call {@link #getDefault} directly!
76
     */
77
    public static synchronized ${TEMPLATENAME}TopComponent findInstance() {
78
        TopComponent win = WindowManager.getDefault().findTopComponent(PREFERRED_ID);
79
        if (win == null) {
80
            Logger.getLogger(${TEMPLATENAME}TopComponent.class.getName()).warning(
81
                    "Cannot find " + PREFERRED_ID + " component. It will not be located properly in the window system.");
82
            return getDefault();
83
        }
84
        if (win instanceof ${TEMPLATENAME}TopComponent) {
85
            return (${TEMPLATENAME}TopComponent)win;
86
        }
87
        Logger.getLogger(${TEMPLATENAME}TopComponent.class.getName()).warning(
88
                "There seem to be multiple components with the '" + PREFERRED_ID +
89
                "' ID. That is a potential source of errors and unexpected behavior.");
90
        return getDefault();
91
    }
92
93
    @Override
94
    public int getPersistenceType() {
95
        return TopComponent.PERSISTENCE_ALWAYS;
96
    }
97
98
    @Override
99
    public void componentOpened() {
100
        // TODO add custom code on component opening
101
    }
102
103
    @Override
104
    public void componentClosed() {
105
        // TODO add custom code on component closing
106
    }
107
108
    void writeProperties(java.util.Properties p) {
109
        // better to version settings since initial version as advocated at
110
        // http://wiki.apidesign.org/wiki/PropertyFiles
111
        p.setProperty("version", "1.0");
112
        // TODO store your settings
113
    }
114
    Object readProperties(java.util.Properties p) {
115
        ${TEMPLATENAME}TopComponent singleton = ${TEMPLATENAME}TopComponent.getDefault();
116
        singleton.readPropertiesImpl(p);
117
        return singleton;
118
    }
119
120
    private void readPropertiesImpl(java.util.Properties p) {
121
        String version = p.getProperty("version");
122
        // TODO read your settings according to their version
123
    }
124
125
    @Override
126
    protected String preferredID() {
127
        return PREFERRED_ID;
128
    }
129
}
(-)b3bbc4d76b98 (+53 lines)
Added Link Here
1
<!--
2
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
4
Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
5
6
7
The contents of this file are subject to the terms of either the GNU
8
General Public License Version 2 only ("GPL") or the Common
9
Development and Distribution License("CDDL") (collectively, the
10
"License"). You may not use this file except in compliance with the
11
License. You can obtain a copy of the License at
12
http://www.netbeans.org/cddl-gplv2.html
13
or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
14
specific language governing permissions and limitations under the
15
License.  When distributing the software, include this License Header
16
Notice in each file and include the License file at
17
nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
18
particular file as subject to the "Classpath" exception as provided
19
by Sun in the GPL Version 2 section of the License file that
20
accompanied this code. If applicable, add the following below the
21
License Header, with the fields enclosed by brackets [] replaced by
22
your own identifying information:
23
"Portions Copyrighted [year] [name of copyright owner]"
24
25
Contributor(s):
26
27
The Original Software is NetBeans. The Initial Developer of the Original
28
Software is Sun Microsystems, Inc. Portions Copyright 2002 Sun
29
Microsystems, Inc. All Rights Reserved.
30
31
If you wish your version of this file to be governed by only the CDDL
32
or only the GPL Version 2, indicate your decision by adding
33
"[Contributor] elects to include this software in this distribution
34
under the [CDDL or GPL Version 2] license." If you do not indicate a
35
single choice of license, a recipient has the option to distribute
36
your version of this file under either the CDDL, the GPL Version 2 or
37
to extend the choice of license to its licensees as provided above.
38
However, if you add GPL Version 2 code and therefore, elected the GPL
39
Version 2 license, then the option applies only if the new code is
40
made subject to such option by the copyright holder.
41
-->
42
43
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
44
45
<HTML>
46
  <HEAD>
47
    <TITLE>org.netbeans.api.settings package</TITLE>
48
  </HEAD>
49
  <BODY>
50
      This package provides annotations to simplify use of
51
      <a href="http://top/org/netbeans/spi/settings/doc-files/api.html">convertors</a>.
52
  </BODY>
53
</HTML>
(-)a/settings/api/doc/org/netbeans/spi/settings/doc-files/api.html (-3 / +5 lines)
Lines 183-189 Link Here
183
</pre>
183
</pre>
184
184
185
To create a persistent instance use method
185
To create a persistent instance use method
186
<a href="@org-openide-loaders@/org/openide/loaders/InstanceDataObject.html#create(org.openide.loaders.DataFolder, java.lang.String, java.lang.Object, org.openide.modules.ModuleInfo)">
186
<a href="@org-openide-loaders@/org/openide/loaders/InstanceDataObject.html#create(org.openide.loaders.DataFolder,%20java.lang.String,%20java.lang.Object,%20org.openide.modules.ModuleInfo)">
187
org.openide.loaders.InstanceDataObject.create</a>. The framework will
187
org.openide.loaders.InstanceDataObject.create</a>. The framework will
188
look up the provider registration for the exact class of the object passed
188
look up the provider registration for the exact class of the object passed
189
into the method.
189
into the method.
Lines 331-338 Link Here
331
<pre>
331
<pre>
332
&lt;ANY-ACCESS-MODIFIER&gt; <font class="type">void</font> <font class="function-name">writeProperties</font>(java.util.<font class="type">Properties</font> <font class="variable-name">p</font>)
332
&lt;ANY-ACCESS-MODIFIER&gt; <font class="type">void</font> <font class="function-name">writeProperties</font>(java.util.<font class="type">Properties</font> <font class="variable-name">p</font>)
333
</pre>
333
</pre>
334
334
It is the setting object concern to collect all properties of its super classes.
335
It is the setting object concern to collect all properties of its super classes. 
335
Since version 1.18, the <code>readProperties</code> can also return an Object.
336
In such case, the <code>XMLPropertiesConvertor</code> replaces the current object
337
with the returned one.
336
<p>
338
<p>
337
The XMLProperties convertor also makes possible to prevent automatic storing
339
The XMLProperties convertor also makes possible to prevent automatic storing
338
of the setting object by using file attribute <code>xmlproperties.preventStoring</code>
340
of the setting object by using file attribute <code>xmlproperties.preventStoring</code>
(-)a/settings/apichanges.xml (+28 lines)
Lines 105-110 Link Here
105
105
106
<!-- ACTUAL CHANGES BEGIN HERE: -->
106
<!-- ACTUAL CHANGES BEGIN HERE: -->
107
  <changes>
107
  <changes>
108
    <change id="readResolveBehaviour">
109
        <api name="settings_spi"/>
110
        <summary>readProperties can designate its replace</summary>
111
        <version major="1" minor="18"/>
112
        <date day="10" month="1" year="2009"/>
113
        <author login="jtulach"/>
114
        <compatibility addition="yes" binary="compatible" deletion="no" deprecation="no" modification="yes" semantic="compatible" source="compatible"/>
115
        <description>
116
            Semantics of <code>readProperties</code> method has been extended
117
            to allow the method to return an object. Read
118
            <a href="@TOP@/org/netbeans/spi/settings/doc-files/api.html#xmlprops">more</a>.
119
        </description>
120
        <issue number="155962"/>
121
    </change>
122
    <change id="convertor.propertyannotation">
123
        <api name="settings_spi"/>
124
        <summary>@ConvertAsProperties annotation</summary>
125
        <version major="1" minor="18"/>
126
        <date day="10" month="1" year="2009"/>
127
        <author login="jtulach"/>
128
        <compatibility addition="yes"/>
129
        <description>
130
            Human friendly way to register XML property based convertor via
131
            the <code>@ConvertAsProperties</code> annotation.
132
        </description>
133
        <class package="org.netbeans.api.settings" name="ConvertAsProperties"/>
134
        <issue number="155962"/>
135
    </change>
108
    <change id="convertor.recognize.xml">
136
    <change id="convertor.recognize.xml">
109
        <api name="settings_spi"/>
137
        <api name="settings_spi"/>
110
        <summary>Allow convertors to recognize .xml files in specially attributed folders.</summary>
138
        <summary>Allow convertors to recognize .xml files in specially attributed folders.</summary>
(-)a/settings/nbproject/project.properties (-1 / +1 lines)
Lines 46-49 Link Here
46
javadoc.main.page=org/netbeans/spi/settings/doc-files/api.html
46
javadoc.main.page=org/netbeans/spi/settings/doc-files/api.html
47
# Extra classpath used to run unit tests
47
# Extra classpath used to run unit tests
48
#test.unit.cp.extra=${core.dir}/core/core.jar:${core.dir}/lib/boot.jar:${core.dir}/core/core.jar
48
#test.unit.cp.extra=${core.dir}/core/core.jar:${core.dir}/lib/boot.jar:${core.dir}/core/core.jar
49
spec.version.base=1.17.0
49
spec.version.base=1.18.0
(-)a/settings/nbproject/project.xml (+1 lines)
Lines 156-161 Link Here
156
                </test-type>
156
                </test-type>
157
            </test-dependencies>
157
            </test-dependencies>
158
            <public-packages>
158
            <public-packages>
159
                <package>org.netbeans.api.settings</package>
159
                <package>org.netbeans.spi.settings</package>
160
                <package>org.netbeans.spi.settings</package>
160
            </public-packages>
161
            </public-packages>
161
        </data>
162
        </data>
(-)b3bbc4d76b98 (+52 lines)
Added Link Here
1
2
package org.netbeans.api.settings;
3
4
import java.lang.annotation.ElementType;
5
import java.lang.annotation.Retention;
6
import java.lang.annotation.RetentionPolicy;
7
import java.lang.annotation.Target;
8
import java.util.Properties;
9
10
/** Annotation to attach to object that is wishing to support conversion from
11
 * and to {@link Properties}. More info about the format and protocol
12
 * <a href="../../spi/settings/doc-files/api.html#xmlprops">is available</a> in separate document,
13
 * here is the shortest possible howto:
14
 * <pre>
15
 * <code>@</code>ConvertAsProperties(dtd="-//Your Org//Your Setting//EN")
16
 * <font class="type">public class</font> YourObject {
17
 *   <font class="type">public</font> YourObject() {} // public constructor is a must
18
 *   <font class="type">void</font> <font class="function-name">readProperties</font>(java.util.<font class="type">Properties</font> <font class="variable-name">p</font>) {
19
 *     // do the read
20
 *   }
21
 *   <font class="type">void</font> <font class="function-name">writeProperties</font>(java.util.<font class="type">Properties</font> <font class="variable-name">p</font>) {
22
 *     // handle the store
23
 *   }
24
 * }
25
 * </pre>
26
 *
27
 * @author Jaroslav Tulach <jtulach@netbeans.org>
28
 * @since 1.18
29
 */
30
@Retention(RetentionPolicy.SOURCE)
31
@Target(ElementType.TYPE)
32
public @interface ConvertAsProperties {
33
    /** constant to return from {@link #ignoreChanges()} to signal that all
34
     * property changes shall be ignored.
35
     */
36
    public static final String IGNORE_ALL_CHANGES = "all";
37
38
    /** Public ID of the XML file that results in creation of the
39
     * annotated type and to which the annotated type can be converted.
40
     * @return public ID of the file's DTD
41
     */
42
    String dtd();
43
    /** Shall every change in the object result in save? Or shall the
44
     * object just be marked as dirty?
45
     */
46
    boolean autostore() default true;
47
    /** An array of properties that are ignored without marking the object
48
     * as dirty or saving it.
49
     * @return array of property names or {@link #IGNORE_ALL_CHANGES} to ignore all properties
50
     */
51
    String[] ignoreChanges() default {};
52
}
(-)b3bbc4d76b98 (+262 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * Contributor(s):
25
 *
26
 * The Original Software is NetBeans. The Initial Developer of the Original
27
 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
28
 * Microsystems, Inc. All Rights Reserved.
29
 *
30
 * If you wish your version of this file to be governed by only the CDDL
31
 * or only the GPL Version 2, indicate your decision by adding
32
 * "[Contributor] elects to include this software in this distribution
33
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
34
 * single choice of license, a recipient has the option to distribute
35
 * your version of this file under either the CDDL, the GPL Version 2 or
36
 * to extend the choice of license to its licensees as provided above.
37
 * However, if you add GPL Version 2 code and therefore, elected the GPL
38
 * Version 2 license, then the option applies only if the new code is
39
 * made subject to such option by the copyright holder.
40
 */
41
42
package org.netbeans.modules.settings.convertors;
43
44
import java.util.Set;
45
import javax.annotation.processing.Processor;
46
import javax.annotation.processing.RoundEnvironment;
47
import javax.annotation.processing.SupportedAnnotationTypes;
48
import javax.annotation.processing.SupportedSourceVersion;
49
import javax.lang.model.SourceVersion;
50
import javax.lang.model.element.Element;
51
import javax.lang.model.element.ExecutableElement;
52
import javax.lang.model.element.Modifier;
53
import javax.lang.model.element.TypeElement;
54
import javax.lang.model.type.TypeKind;
55
import javax.lang.model.type.TypeMirror;
56
import javax.lang.model.util.ElementFilter;
57
import org.netbeans.api.settings.ConvertAsProperties;
58
import org.openide.filesystems.annotations.LayerBuilder.File;
59
import org.openide.filesystems.annotations.LayerGeneratingProcessor;
60
import org.openide.filesystems.annotations.LayerGenerationException;
61
import org.openide.util.lookup.ServiceProvider;
62
63
/** Processor to hide all the complexities of settings layer registration.
64
 *
65
 * @author Jaroslav Tulach <jtulach@netbeans.org>
66
 */
67
@ServiceProvider(service=Processor.class)
68
@SupportedSourceVersion(SourceVersion.RELEASE_6)
69
@SupportedAnnotationTypes("org.netbeans.api.settings.ConvertAsProperties")//NOI18N
70
public class ConvertorProcessor extends LayerGeneratingProcessor {
71
72
73
    @Override
74
    protected boolean handleProcess(
75
        Set<? extends TypeElement> annotations,
76
        RoundEnvironment env
77
    ) throws LayerGenerationException {
78
        if (env.processingOver()) {
79
            return false;
80
        }
81
82
        for (Element e : env.getElementsAnnotatedWith(ConvertAsProperties.class)) {
83
            ConvertAsProperties reg = e.getAnnotation(ConvertAsProperties.class);
84
85
            String convElem = instantiableClassOrMethod(e);
86
            final String dtd = reg.dtd();
87
88
            String dtdCode = convertPublicId(dtd);
89
90
                /*
91
            <folder name="xml">
92
             <folder name="entities">
93
              <folder name="NetBeans_org_netbeans_modules_settings_xtest">
94
                <file name="DTD_XML_FooSetting_1_0" url="nbres:/org/netbeans/modules/settings/resources/properties-1_0.dtd">
95
                    <attr name="hint.originalPublicID" stringvalue="-//NetBeans org.netbeans.modules.settings.xtest//DTD XML FooSetting 1.0//EN"/>
96
                 */
97
            layer(e).file("xml/entities" + dtdCode).
98
                url("nbres:/org/netbeans/modules/settings/resources/properties-1_0.dtd").
99
                stringvalue("hint.originalPublicID", dtd).write();
100
       /*
101
        <folder name="memory">
102
            <folder name="org">
103
                <folder name="netbeans">
104
                    <folder name="modules">
105
                        <folder name="settings">
106
                            <folder name="convertors">
107
                                <file name="FooSetting">
108
                                    <attr name="settings.providerPath"
109
                                    stringvalue="xml/lookups/NetBeans_org_netbeans_modules_settings_xtest/DTD_XML_FooSetting_1_0.instance"/>
110
           */
111
            layer(e).file("xml/memory/" + convElem.replace('.', '/')).
112
                stringvalue("settings.providerPath", "xml/lookups/" + dtdCode + ".instance").
113
                write();
114
115
       /*
116
        <folder name="lookups">
117
            <folder name="NetBeans_org_netbeans_modules_settings_xtest">
118
                <file name="DTD_XML_FooSetting_1_0.instance">
119
                    <attr name="instanceCreate" methodvalue="org.netbeans.api.settings.Factory.create"/>
120
                    <attr name="settings.convertor" methodvalue="org.netbeans.api.settings.Factory.properties"/>
121
                    <attr name="settings.instanceClass" stringvalue="org.netbeans.modules.settings.convertors.FooSetting"/>
122
                    <attr name="settings.instanceOf" stringvalue="org.netbeans.modules.settings.convertors.FooSetting"/>
123
                </file>
124
            </folder>
125
        */
126
            File f = layer(e).file("xml/lookups" + dtdCode + ".instance").
127
                methodvalue("instanceCreate", "org.netbeans.api.settings.Factory", "create").
128
                methodvalue("settings.convertor", "org.netbeans.api.settings.Factory", "properties").
129
                stringvalue("settings.instanceClass", convElem).
130
                stringvalue("settings.instanceOf", convElem).
131
                boolvalue("xmlproperties.preventStoring", !reg.autostore());
132
            commaSeparated(f, reg.ignoreChanges()).write();
133
        }
134
        return false;
135
    }
136
137
    /** Copied from FileEntityResolver from o.n.core module.
138
     */
139
    @SuppressWarnings("fallthrough")
140
    private static String convertPublicId (String publicID) {
141
        char[] arr = publicID.toCharArray ();
142
143
144
        int numberofslashes = 0;
145
        int state = 0;
146
        int write = 0;
147
        OUT: for (int i = 0; i < arr.length; i++) {
148
            char ch = arr[i];
149
150
            switch (state) {
151
            case 0:
152
                // initial state
153
                if (ch == '+' || ch == '-' || ch == 'I' || ch == 'S' || ch == 'O') {
154
                    // do not write that char
155
                    continue;
156
                }
157
                // switch to regular state
158
                state = 1;
159
                // fallthru
160
            case 1:
161
                // regular state expecting any character
162
                if (ch == '/') {
163
                    state = 2;
164
                    if (++numberofslashes == 3) {
165
                        // last part of the ID, exit
166
                        break OUT;
167
                    }
168
                    arr[write++] = '/';
169
                    continue;
170
                }
171
                break;
172
            case 2:
173
                // previous character was /
174
                if (ch == '/') {
175
                    // ignore second / and write nothing
176
                    continue;
177
                }
178
                state = 1;
179
                break;
180
            }
181
182
            // write the char into the array
183
            if (ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z' || ch >= '0' && ch <= '9') {
184
                arr[write++] = ch;
185
            } else {
186
                arr[write++] = '_';
187
            }
188
        }
189
190
        return new String (arr, 0, write);
191
    }
192
193
    private static File commaSeparated(File f, String[] arr) {
194
        if (arr.length == 0) {
195
            return f;
196
        }
197
198
        StringBuilder sb = new StringBuilder();
199
        String sep = "";
200
        for (String s : arr) {
201
            sb.append(sep);
202
            sb.append(s);
203
            sep = ",";
204
        }
205
        return f.stringvalue("xmlproperties.ignoreChanges", sb.toString());
206
    }
207
208
    private String instantiableClassOrMethod(Element e) throws IllegalArgumentException, LayerGenerationException {
209
        switch (e.getKind()) {
210
            case CLASS: {
211
                String clazz = processingEnv.getElementUtils().getBinaryName((TypeElement) e).toString();
212
                if (e.getModifiers().contains(Modifier.ABSTRACT)) {
213
                    throw new LayerGenerationException(clazz + " must not be abstract", e);
214
                }
215
                {
216
                    boolean hasDefaultCtor = false;
217
                    for (ExecutableElement constructor : ElementFilter.constructorsIn(e.getEnclosedElements())) {
218
                        if (constructor.getParameters().isEmpty()) {
219
                            hasDefaultCtor = true;
220
                            break;
221
                        }
222
                    }
223
                    if (!hasDefaultCtor) {
224
                        throw new LayerGenerationException(clazz + " must have a no-argument constructor", e);
225
                    }
226
                }
227
                TypeMirror propType;
228
                propType = processingEnv.getElementUtils().getTypeElement("java.util.Properties").asType();
229
                {
230
                    boolean hasRead = false;
231
                    boolean hasWrite = false;
232
                    for (ExecutableElement m : ElementFilter.methodsIn(e.getEnclosedElements())) {
233
                        if (
234
                            m.getParameters().size() == 1 && 
235
                            m.getSimpleName().contentEquals("readProperties") &&
236
                            m.getParameters().get(0).asType().equals(propType)
237
                        ) {
238
                            hasRead = true;
239
                        }
240
                        if (
241
                            m.getParameters().size() == 1 &&
242
                            m.getSimpleName().contentEquals("writeProperties") &&
243
                            m.getParameters().get(0).asType().equals(propType) &&
244
                            m.getReturnType().getKind() == TypeKind.VOID
245
                        ) {
246
                            hasWrite = true;
247
                        }
248
                    }
249
                    if (!hasRead) {
250
                        throw new LayerGenerationException(clazz + " must have proper readProperties method", e);
251
                    }
252
                    if (!hasWrite) {
253
                        throw new LayerGenerationException(clazz + " must have proper writeProperties method", e);
254
                    }
255
                }
256
                return clazz;
257
            }
258
            default:
259
                throw new IllegalArgumentException("Annotated element is not loadable as an instance: " + e);
260
        }
261
    }
262
}
(-)a/settings/src/org/netbeans/modules/settings/convertors/XMLPropertiesConvertor.java (-4 / +9 lines)
Lines 93-100 Link Here
93
    
93
    
94
    public Object read(java.io.Reader r) throws IOException, ClassNotFoundException {
94
    public Object read(java.io.Reader r) throws IOException, ClassNotFoundException {
95
        Object def = defaultInstanceCreate();
95
        Object def = defaultInstanceCreate();
96
        readSetting(r, def);
96
        return readSetting(r, def);
97
        return def;
98
    }
97
    }
99
    
98
    
100
    public void write(java.io.Writer w, Object inst) throws IOException {
99
    public void write(java.io.Writer w, Object inst) throws IOException {
Lines 243-249 Link Here
243
        return ((ClassLoader)Lookup.getDefault().lookup(ClassLoader.class)).loadClass(instanceClass);
242
        return ((ClassLoader)Lookup.getDefault().lookup(ClassLoader.class)).loadClass(instanceClass);
244
    }
243
    }
245
    
244
    
246
    private void readSetting(java.io.Reader input, Object inst) throws IOException {
245
    private Object readSetting(java.io.Reader input, Object inst) throws IOException {
247
        try {
246
        try {
248
            java.lang.reflect.Method m = inst.getClass().getDeclaredMethod(
247
            java.lang.reflect.Method m = inst.getClass().getDeclaredMethod(
249
                "readProperties", new Class[] {Properties.class}); // NOI18N
248
                "readProperties", new Class[] {Properties.class}); // NOI18N
Lines 251-257 Link Here
251
            XMLPropertiesConvertor.Reader r = new XMLPropertiesConvertor.Reader();
250
            XMLPropertiesConvertor.Reader r = new XMLPropertiesConvertor.Reader();
252
            r.parse(input);
251
            r.parse(input);
253
            m.setAccessible(true);
252
            m.setAccessible(true);
254
            m.invoke(inst, new Object[] {r.getProperties()});
253
            Object ret = m.invoke(inst, new Object[] {r.getProperties()});
254
            if (ret == null) {
255
                ret = inst;
256
            }
257
            return ret;
255
        } catch (NoSuchMethodException ex) {
258
        } catch (NoSuchMethodException ex) {
256
            IOException ioe = new IOException(ex.getMessage());
259
            IOException ioe = new IOException(ex.getMessage());
257
            ioe.initCause(ex);
260
            ioe.initCause(ex);
Lines 317-322 Link Here
317
        private Properties props = new Properties();
320
        private Properties props = new Properties();
318
        private String publicId;
321
        private String publicId;
319
322
323
        @Override
320
        public org.xml.sax.InputSource resolveEntity(String publicId, String systemId)
324
        public org.xml.sax.InputSource resolveEntity(String publicId, String systemId)
321
        throws SAXException {
325
        throws SAXException {
322
            if (this.publicId != null && this.publicId.equals (publicId)) {
326
            if (this.publicId != null && this.publicId.equals (publicId)) {
Lines 326-331 Link Here
326
            }
330
            }
327
        }
331
        }
328
332
333
        @Override
329
        public void startElement(String uri, String localName, String qName, org.xml.sax.Attributes attribs) throws SAXException {
334
        public void startElement(String uri, String localName, String qName, org.xml.sax.Attributes attribs) throws SAXException {
330
            if (ELM_PROPERTY.equals(qName)) {
335
            if (ELM_PROPERTY.equals(qName)) {
331
                String propertyName = attribs.getValue(ATR_PROPERTY_NAME);
336
                String propertyName = attribs.getValue(ATR_PROPERTY_NAME);
(-)b3bbc4d76b98 (+169 lines)
Added Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
5
 *
6
 * The contents of this file are subject to the terms of either the GNU
7
 * General Public License Version 2 only ("GPL") or the Common
8
 * Development and Distribution License("CDDL") (collectively, the
9
 * "License"). You may not use this file except in compliance with the
10
 * License. You can obtain a copy of the License at
11
 * http://www.netbeans.org/cddl-gplv2.html
12
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13
 * specific language governing permissions and limitations under the
14
 * License.  When distributing the software, include this License Header
15
 * Notice in each file and include the License file at
16
 * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
17
 * particular file as subject to the "Classpath" exception as provided
18
 * by Sun in the GPL Version 2 section of the License file that
19
 * accompanied this code. If applicable, add the following below the
20
 * License Header, with the fields enclosed by brackets [] replaced by
21
 * your own identifying information:
22
 * "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * Contributor(s):
25
 *
26
 * The Original Software is NetBeans. The Initial Developer of the Original
27
 * Software is Sun Microsystems, Inc. Portions Copyright 2002 Sun
28
 * Microsystems, Inc. All Rights Reserved.
29
 *
30
 * If you wish your version of this file to be governed by only the CDDL
31
 * or only the GPL Version 2, indicate your decision by adding
32
 * "[Contributor] elects to include this software in this distribution
33
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
34
 * single choice of license, a recipient has the option to distribute
35
 * your version of this file under either the CDDL, the GPL Version 2 or
36
 * to extend the choice of license to its licensees as provided above.
37
 * However, if you add GPL Version 2 code and therefore, elected the GPL
38
 * Version 2 license, then the option applies only if the new code is
39
 * made subject to such option by the copyright holder.
40
 */
41
42
package org.netbeans.modules.settings.convertors;
43
44
import java.io.*;
45
46
import java.util.Properties;
47
import org.netbeans.junit.NbTestCase;
48
49
50
import org.netbeans.api.settings.ConvertAsProperties;
51
import org.netbeans.spi.settings.Convertor;
52
53
import org.openide.filesystems.FileObject;
54
import org.openide.filesystems.Repository;
55
import org.openide.util.test.AnnotationProcessorTestUtils;
56
57
/** Checks usage of annotation to assign XML properties convertor.
58
 *
59
 * @author Jaroslav Tulach
60
 */
61
public final class XMLPropertiesConvertorAnnotationTest extends NbTestCase {
62
    /** Creates a new instance of XMLPropertiesConvertorTest */
63
    public XMLPropertiesConvertorAnnotationTest(String name) {
64
        super(name);
65
    }
66
67
    @Override
68
    protected void setUp() throws Exception {
69
        clearWorkDir();
70
    }
71
    
72
    public void testReadWrite() throws Exception {
73
        FileObject dtdFO = Repository.getDefault().getDefaultFileSystem().
74
            findResource("/xml/lookups/NetBeans_org_netbeans_modules_settings_xtest/DTD_XML_FooSetting_2_0.instance");
75
        assertNotNull("Provider not found", dtdFO);
76
        Convertor c = XMLPropertiesConvertor.create(dtdFO);
77
        AnnoFoo foo = new AnnoFoo();
78
        foo.setProperty1("xxx");
79
        CharArrayWriter caw = new CharArrayWriter(1024);
80
        c.write(caw, foo);
81
        caw.flush();
82
        caw.close();
83
        CharArrayReader car = new CharArrayReader(caw.toCharArray());
84
        Object obj = c.read(car);
85
        assertEquals(foo, obj);
86
        assertEquals("HooFoo is the class", HooFoo.class, obj.getClass());
87
    }
88
89
    @ConvertAsProperties(
90
        dtd="-//NetBeans org.netbeans.modules.settings.xtest//DTD XML FooSetting 2.0//EN"
91
    )
92
    public static class AnnoFoo extends FooSetting {
93
        public Object readProperties(Properties p) {
94
            HooFoo n = new HooFoo();
95
            n.setProperty1(p.getProperty("p1"));
96
            return n;
97
        }
98
        public void writeProperties(Properties p) {
99
            p.setProperty("p1", this.getProperty1());
100
        }
101
    }
102
    public static class HooFoo extends AnnoFoo {
103
    }
104
105
    public void testVerifyHaveDefaultConstructor() throws Exception {
106
        AnnotationProcessorTestUtils.makeSource(getWorkDir(), "x.y.Kuk",
107
            "import org.netbeans.api.settings.ConvertAsProperties;\n" +
108
            "@ConvertAsProperties(dtd=\"-//x.y//Kuk//EN\")\n" +
109
            "public class Kuk {\n" +
110
            "  public Kuk(int i) {}\n" +
111
            "}\n"
112
        );
113
        ByteArrayOutputStream err = new ByteArrayOutputStream();
114
        boolean res = AnnotationProcessorTestUtils.runJavac(getWorkDir(), null, getWorkDir(), null, err);
115
        assertFalse("Should fail", res);
116
        if (err.toString().indexOf("x.y.Kuk must have a no-argument constructor") == -1) {
117
            fail("Wrong error message:\n" + err.toString());
118
        }
119
    }
120
    public void testVerifyReadProperties() throws Exception {
121
        AnnotationProcessorTestUtils.makeSource(getWorkDir(), "x.y.Kuk",
122
            "import org.netbeans.api.settings.ConvertAsProperties;\n" +
123
            "@ConvertAsProperties(dtd=\"-//x.y//Kuk//EN\")\n" +
124
            "public class Kuk {\n" +
125
            "  public Kuk() {}\n" +
126
            "  public void writeProperties(java.util.Properties p){}\n" +
127
            "}\n"
128
        );
129
        ByteArrayOutputStream err = new ByteArrayOutputStream();
130
        boolean res = AnnotationProcessorTestUtils.runJavac(getWorkDir(), null, getWorkDir(), null, err);
131
        assertFalse("Should fail", res);
132
        if (err.toString().indexOf("x.y.Kuk must have proper readProperties method") == -1) {
133
            fail("Wrong error message:\n" + err.toString());
134
        }
135
    }
136
    public void testVerifyWriteProperties() throws Exception {
137
        AnnotationProcessorTestUtils.makeSource(getWorkDir(), "x.y.Kuk",
138
            "import org.netbeans.api.settings.ConvertAsProperties;\n" +
139
            "@ConvertAsProperties(dtd=\"-//x.y//Kuk//EN\")\n" +
140
            "public class Kuk {\n" +
141
            "  public Kuk() {}\n" +
142
            "  public void readProperties(java.util.Properties p){}\n" +
143
            "}\n"
144
        );
145
        ByteArrayOutputStream err = new ByteArrayOutputStream();
146
        boolean res = AnnotationProcessorTestUtils.runJavac(getWorkDir(), null, getWorkDir(), null, err);
147
        assertFalse("Should fail", res);
148
        if (err.toString().indexOf("x.y.Kuk must have proper writeProperties method") == -1) {
149
            fail("Wrong error message:\n" + err.toString());
150
        }
151
    }
152
    public void testVerifyWritePropertiesReturnsVoid() throws Exception {
153
        AnnotationProcessorTestUtils.makeSource(getWorkDir(), "x.y.Kuk",
154
            "import org.netbeans.api.settings.ConvertAsProperties;\n" +
155
            "@ConvertAsProperties(dtd=\"-//x.y//Kuk//EN\")\n" +
156
            "public class Kuk {\n" +
157
            "  public Kuk() {}\n" +
158
            "  public void readProperties(java.util.Properties p){}\n" +
159
            "  public int writeProperties(java.util.Properties p){}\n" +
160
            "}\n"
161
        );
162
        ByteArrayOutputStream err = new ByteArrayOutputStream();
163
        boolean res = AnnotationProcessorTestUtils.runJavac(getWorkDir(), null, getWorkDir(), null, err);
164
        assertFalse("Should fail", res);
165
        if (err.toString().indexOf("x.y.Kuk must have proper writeProperties method") == -1) {
166
            fail("Wrong error message:\n" + err.toString());
167
        }
168
    }
169
}

Return to bug 155962