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/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,
(-)a/apisupport.project/src/org/netbeans/modules/apisupport/project/ui/wizard/winsys/templateTopComponentAnno.javx (+128 lines)
Line 0 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.Utilities;
13
14
/**
15
 * Top component which displays something.
16
 */
17
@org.netbeans.api.settings.ConvertAsProperties(
18
    dtd="-//${PACKAGENAME}//${TEMPLATENAME}//EN",
19
    autostore=false
20
)
21
public final class ${TEMPLATENAME}TopComponent extends TopComponent {
22
23
    private static ${TEMPLATENAME}TopComponent instance;
24
    /** path to the icon used by the component and its open action */
25
${COMMENTICON}    static final String ICON_PATH = "${ICONPATH}";
26
27
    private static final String PREFERRED_ID = "${TEMPLATENAME}TopComponent";
28
29
    public ${TEMPLATENAME}TopComponent() {
30
        initComponents();
31
        setName(NbBundle.getMessage(${TEMPLATENAME}TopComponent.class, "CTL_${TEMPLATENAME}TopComponent"));
32
        setToolTipText(NbBundle.getMessage(${TEMPLATENAME}TopComponent.class, "HINT_${TEMPLATENAME}TopComponent"));
33
${COMMENTICON}        setIcon(Utilities.loadImage(ICON_PATH, true));
34
        ${KEEPPREFSIZE}
35
    }
36
37
    /** This method is called from within the constructor to
38
     * initialize the form.
39
     * WARNING: Do NOT modify this code. The content of this method is
40
     * always regenerated by the Form Editor.
41
     */
42
    // <editor-fold defaultstate="collapsed" desc=" Generated Code ">//GEN-BEGIN:initComponents
43
    private void initComponents() {
44
45
        org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(this);
46
        this.setLayout(layout);
47
        layout.setHorizontalGroup(
48
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
49
            .add(0, 400, Short.MAX_VALUE)
50
        );
51
        layout.setVerticalGroup(
52
            layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
53
            .add(0, 300, Short.MAX_VALUE)
54
        );
55
    }// </editor-fold>//GEN-END:initComponents
56
57
58
    // Variables declaration - do not modify//GEN-BEGIN:variables
59
    // End of variables declaration//GEN-END:variables
60
61
    /**
62
     * Gets default instance. Do not use directly: reserved for *.settings files only,
63
     * i.e. deserialization routines; otherwise you could get a non-deserialized instance.
64
     * To obtain the singleton instance, use {@link #findInstance}.
65
     */
66
    public static synchronized ${TEMPLATENAME}TopComponent getDefault() {
67
        if (instance == null) {
68
            instance = new ${TEMPLATENAME}TopComponent();
69
        }
70
        return instance;
71
    }
72
73
    /**
74
     * Obtain the ${TEMPLATENAME}TopComponent instance. Never call {@link #getDefault} directly!
75
     */
76
    public static synchronized ${TEMPLATENAME}TopComponent findInstance() {
77
        TopComponent win = WindowManager.getDefault().findTopComponent(PREFERRED_ID);
78
        if (win == null) {
79
            Logger.getLogger(${TEMPLATENAME}TopComponent.class.getName()).warning(
80
                    "Cannot find " + PREFERRED_ID + " component. It will not be located properly in the window system.");
81
            return getDefault();
82
        }
83
        if (win instanceof ${TEMPLATENAME}TopComponent) {
84
            return (${TEMPLATENAME}TopComponent)win;
85
        }
86
        Logger.getLogger(${TEMPLATENAME}TopComponent.class.getName()).warning(
87
                "There seem to be multiple components with the '" + PREFERRED_ID +
88
                "' ID. That is a potential source of errors and unexpected behavior.");
89
        return getDefault();
90
    }
91
92
    @Override
93
    public int getPersistenceType() {
94
        return TopComponent.PERSISTENCE_ALWAYS;
95
    }
96
97
    @Override
98
    public void componentOpened() {
99
        // TODO add custom code on component opening
100
    }
101
102
    @Override
103
    public void componentClosed() {
104
        // TODO add custom code on component closing
105
    }
106
107
    void writeProperties(java.util.Properties p) {
108
        // better to version settings since initial version as advocated at
109
        // http://wiki.apidesign.org/wiki/PropertyFiles
110
        p.setProperty("version", "1.0");
111
        // TODO store your settings
112
    }
113
    Object readProperties(java.util.Properties p) {
114
        ${TEMPLATENAME}TopComponent singleton = ${TEMPLATENAME}TopComponent.getDefault();
115
        singleton.readPropertiesImpl(p);
116
        return singleton;
117
    }
118
119
    private void readPropertiesImpl(java.util.Properties p) {
120
        String version = p.getProperty("version");
121
        // TODO read your settings according to their version
122
    }
123
124
    @Override
125
    protected String preferredID() {
126
        return PREFERRED_ID;
127
    }
128
}
(-)a/core.startup/src/org/netbeans/core/startup/NbInstaller.java (-8 / +11 lines)
Lines 49-59 Link Here
49
import java.net.URL;
49
import java.net.URL;
50
import java.nio.ByteBuffer;
50
import java.nio.ByteBuffer;
51
import java.util.ArrayList;
51
import java.util.ArrayList;
52
import java.util.Collection;
52
import java.util.Collections;
53
import java.util.Collections;
53
import java.util.Date;
54
import java.util.Date;
54
import java.util.Enumeration;
55
import java.util.Enumeration;
55
import java.util.HashMap;
56
import java.util.HashMap;
56
import java.util.HashSet;
57
import java.util.HashSet;
58
import java.util.LinkedHashSet;
57
import java.util.LinkedList;
59
import java.util.LinkedList;
58
import java.util.List;
60
import java.util.List;
59
import java.util.Locale;
61
import java.util.Locale;
Lines 543-562 Link Here
543
        // #23609: dependent modules should be able to override:
545
        // #23609: dependent modules should be able to override:
544
        modules = new ArrayList<Module>(modules);
546
        modules = new ArrayList<Module>(modules);
545
        Collections.reverse(modules);
547
        Collections.reverse(modules);
546
        Map<ModuleLayeredFileSystem,List<URL>> urls = new HashMap<ModuleLayeredFileSystem,List<URL>>(5);
548
        Map<ModuleLayeredFileSystem,Collection<URL>> urls = new HashMap<ModuleLayeredFileSystem,Collection<URL>>(5);
547
        ModuleLayeredFileSystem userModuleLayer = ModuleLayeredFileSystem.getUserModuleLayer();
549
        ModuleLayeredFileSystem userModuleLayer = ModuleLayeredFileSystem.getUserModuleLayer();
548
        ModuleLayeredFileSystem installationModuleLayer = ModuleLayeredFileSystem.getInstallationModuleLayer();
550
        ModuleLayeredFileSystem installationModuleLayer = ModuleLayeredFileSystem.getInstallationModuleLayer();
549
        urls.put(userModuleLayer, new ArrayList<URL>(1000));
551
        urls.put(userModuleLayer, new LinkedHashSet<URL>(1000));
550
        urls.put(installationModuleLayer, new ArrayList<URL>(1000));
552
        urls.put(installationModuleLayer, new LinkedHashSet<URL>(1000));
551
        for (Module m: modules) {
553
        for (Module m: modules) {
552
            // #19458: only put reloadables into the "session layer"
554
            // #19458: only put reloadables into the "session layer"
553
            // (where they will not have their layers cached). All others
555
            // (where they will not have their layers cached). All others
554
            // should go into "installation layer" (so that they can mask
556
            // should go into "installation layer" (so that they can mask
555
            // layers according to cross-dependencies).
557
            // layers according to cross-dependencies).
556
            ModuleLayeredFileSystem host = m.isReloadable() ? userModuleLayer : installationModuleLayer;
558
            ModuleLayeredFileSystem host = m.isReloadable() ? userModuleLayer : installationModuleLayer;
557
            List<URL> theseurls = urls.get(host);
559
            Collection<URL> theseurls = urls.get(host);
558
            if (theseurls == null) {
560
            if (theseurls == null) {
559
                theseurls = new ArrayList<URL>(1000);
561
                theseurls = new LinkedHashSet<URL>(1000);
560
                urls.put(host, theseurls);
562
                urls.put(host, theseurls);
561
            }
563
            }
562
            ClassLoader cl = m.getClassLoader();
564
            ClassLoader cl = m.getClassLoader();
Lines 595-610 Link Here
595
                findResources.setAccessible(true);
597
                findResources.setAccessible(true);
596
                Enumeration e = (Enumeration) findResources.invoke(cl, "META-INF/generated-layer.xml"); // NOI18N
598
                Enumeration e = (Enumeration) findResources.invoke(cl, "META-INF/generated-layer.xml"); // NOI18N
597
                while (e.hasMoreElements()) {
599
                while (e.hasMoreElements()) {
598
                    theseurls.add((URL) e.nextElement());
600
                    URL u = (URL)e.nextElement();
601
                    theseurls.add(u);
599
                }
602
                }
600
            } catch (Exception x) {
603
            } catch (Exception x) {
601
                Exceptions.printStackTrace(x);
604
                Exceptions.printStackTrace(x);
602
            }
605
            }
603
        }
606
        }
604
        // Now actually do it.
607
        // Now actually do it.
605
        for (Map.Entry<ModuleLayeredFileSystem,List<URL>> entry: urls.entrySet()) {
608
        for (Map.Entry<ModuleLayeredFileSystem,Collection<URL>> entry: urls.entrySet()) {
606
            ModuleLayeredFileSystem host = entry.getKey();
609
            ModuleLayeredFileSystem host = entry.getKey();
607
            List<URL> theseurls = entry.getValue();
610
            Collection<URL> theseurls = entry.getValue();
608
            Util.err.fine("Adding/removing layer URLs: host=" + host + " urls=" + theseurls);
611
            Util.err.fine("Adding/removing layer URLs: host=" + host + " urls=" + theseurls);
609
            try {
612
            try {
610
                if (load) {
613
                if (load) {
(-)a/settings/api/doc/org/netbeans/api/settings/package.html (+53 lines)
Line 0 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 (+14 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="convertor.propertyannotation">
109
        <api name="settings_spi"/>
110
        <summary>@ConvertAsProperties annotation</summary>
111
        <version major="1" minor="18"/>
112
        <date day="10" month="1" year="2009"/>
113
        <author login="jtulach"/>
114
        <compatibility addition="yes"/>
115
        <description>
116
            Human friendly way to register XML property based convertor via
117
            the <code>@ConvertAsProperties</code> annotation.
118
        </description>
119
        <class package="org.netbeans.api.settings" name="ConvertAsProperties"/>
120
        <issue number="155962"/>
121
    </change>
108
    <change id="convertor.recognize.xml">
122
    <change id="convertor.recognize.xml">
109
        <api name="settings_spi"/>
123
        <api name="settings_spi"/>
110
        <summary>Allow convertors to recognize .xml files in specially attributed folders.</summary>
124
        <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>
(-)a/settings/src/org/netbeans/api/settings/ConvertAsProperties.java (+47 lines)
Line 0 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
    /** Public ID of the XML file that results in creation of the
34
     * annotated type and to which the annotated type can be converted.
35
     * @return public ID of the file's DTD
36
     */
37
    String dtd();
38
    /** Shall every change in the object result in save? Or shall the
39
     * object just be marked as dirty?
40
     */
41
    boolean autostore() default true;
42
    /** An array of properties that are ignored without marking the object
43
     * as dirty or saving it.
44
     * @return array of property names or "all" to ignore all properties
45
     */
46
    String[] ignoreChanges() default {};
47
}
(-)a/settings/src/org/netbeans/modules/settings/convertors/ConvertorProcessor.java (+246 lines)
Line 0 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.TypeMirror;
55
import javax.lang.model.util.ElementFilter;
56
import org.netbeans.api.settings.ConvertAsProperties;
57
import org.openide.filesystems.annotations.LayerBuilder.File;
58
import org.openide.filesystems.annotations.LayerGeneratingProcessor;
59
import org.openide.filesystems.annotations.LayerGenerationException;
60
import org.openide.util.lookup.ServiceProvider;
61
62
/** Processor to hide all the complexities of settings layer registration.
63
 *
64
 * @author Jaroslav Tulach <jtulach@netbeans.org>
65
 */
66
@ServiceProvider(service=Processor.class)
67
@SupportedSourceVersion(SourceVersion.RELEASE_6)
68
@SupportedAnnotationTypes("org.netbeans.api.settings.ConvertAsProperties")//NOI18N
69
public class ConvertorProcessor extends LayerGeneratingProcessor {
70
71
72
    @Override
73
    protected boolean handleProcess(
74
        Set<? extends TypeElement> annotations,
75
        RoundEnvironment env
76
    ) throws LayerGenerationException {
77
        for (Element e : env.getElementsAnnotatedWith(ConvertAsProperties.class)) {
78
            ConvertAsProperties reg = e.getAnnotation(ConvertAsProperties.class);
79
80
            String[] convElem = instantiableClassOrMethod(e, null);
81
            final String dtd = reg.dtd();
82
83
            String dtdCode = convertPublicId(dtd);
84
85
                /*
86
            <folder name="xml">
87
             <folder name="entities">
88
              <folder name="NetBeans_org_netbeans_modules_settings_xtest">
89
                <file name="DTD_XML_FooSetting_1_0" url="nbres:/org/netbeans/modules/settings/resources/properties-1_0.dtd">
90
                    <attr name="hint.originalPublicID" stringvalue="-//NetBeans org.netbeans.modules.settings.xtest//DTD XML FooSetting 1.0//EN"/>
91
                 */
92
            layer(e).file("xml/entities" + dtdCode).
93
                url("nbres:/org/netbeans/modules/settings/resources/properties-1_0.dtd").
94
                stringvalue("hint.originalPublicID", dtd).write();
95
       /*
96
        <folder name="memory">
97
            <folder name="org">
98
                <folder name="netbeans">
99
                    <folder name="modules">
100
                        <folder name="settings">
101
                            <folder name="convertors">
102
                                <file name="FooSetting">
103
                                    <attr name="settings.providerPath"
104
                                    stringvalue="xml/lookups/NetBeans_org_netbeans_modules_settings_xtest/DTD_XML_FooSetting_1_0.instance"/>
105
           */
106
            layer(e).file("xml/memory/" + convElem[0].replace('.', '/')).
107
                stringvalue("settings.providerPath", "xml/lookups/" + dtdCode + ".instance").
108
                write();
109
110
       /*
111
        <folder name="lookups">
112
            <folder name="NetBeans_org_netbeans_modules_settings_xtest">
113
                <file name="DTD_XML_FooSetting_1_0.instance">
114
                    <attr name="instanceCreate" methodvalue="org.netbeans.api.settings.Factory.create"/>
115
                    <attr name="settings.convertor" methodvalue="org.netbeans.api.settings.Factory.properties"/>
116
                    <attr name="settings.instanceClass" stringvalue="org.netbeans.modules.settings.convertors.FooSetting"/>
117
                    <attr name="settings.instanceOf" stringvalue="org.netbeans.modules.settings.convertors.FooSetting"/>
118
                </file>
119
            </folder>
120
        */
121
            File f = layer(e).file("xml/lookups" + dtdCode + ".instance").
122
                methodvalue("instanceCreate", "org.netbeans.api.settings.Factory", "create").
123
                methodvalue("settings.convertor", "org.netbeans.api.settings.Factory", "properties").
124
                stringvalue("settings.instanceClass", convElem[0]).
125
                stringvalue("settings.instanceOf", convElem[0]).
126
                boolvalue("xmlproperties.preventStoring", !reg.autostore());
127
            commaSeparated(f, reg.ignoreChanges()).write();
128
        }
129
        return false;
130
    }
131
132
    /** Copied from FileEntityResolver from o.n.core module.
133
     */
134
    @SuppressWarnings("fallthrough")
135
    private static String convertPublicId (String publicID) {
136
        char[] arr = publicID.toCharArray ();
137
138
139
        int numberofslashes = 0;
140
        int state = 0;
141
        int write = 0;
142
        OUT: for (int i = 0; i < arr.length; i++) {
143
            char ch = arr[i];
144
145
            switch (state) {
146
            case 0:
147
                // initial state
148
                if (ch == '+' || ch == '-' || ch == 'I' || ch == 'S' || ch == 'O') {
149
                    // do not write that char
150
                    continue;
151
                }
152
                // switch to regular state
153
                state = 1;
154
                // fallthru
155
            case 1:
156
                // regular state expecting any character
157
                if (ch == '/') {
158
                    state = 2;
159
                    if (++numberofslashes == 3) {
160
                        // last part of the ID, exit
161
                        break OUT;
162
                    }
163
                    arr[write++] = '/';
164
                    continue;
165
                }
166
                break;
167
            case 2:
168
                // previous character was /
169
                if (ch == '/') {
170
                    // ignore second / and write nothing
171
                    continue;
172
                }
173
                state = 1;
174
                break;
175
            }
176
177
            // write the char into the array
178
            if (ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z' || ch >= '0' && ch <= '9') {
179
                arr[write++] = ch;
180
            } else {
181
                arr[write++] = '_';
182
            }
183
        }
184
185
        return new String (arr, 0, write);
186
    }
187
188
    private static File commaSeparated(File f, String[] arr) {
189
        if (arr.length == 0) {
190
            return f;
191
        }
192
193
        StringBuilder sb = new StringBuilder();
194
        String sep = "";
195
        for (String s : arr) {
196
            sb.append(sep);
197
            sb.append(s);
198
            sep = ",";
199
        }
200
        return f.stringvalue("xmlproperties.ignoreChanges", sb.toString());
201
    }
202
203
    private String[] instantiableClassOrMethod(Element e, Class type) throws IllegalArgumentException, LayerGenerationException {
204
        TypeMirror typeMirror = type != null ? processingEnv.getElementUtils().getTypeElement(type.getName().replace('$', '.')).asType() : null;
205
        switch (e.getKind()) {
206
            case CLASS: {
207
                String clazz = processingEnv.getElementUtils().getBinaryName((TypeElement) e).toString();
208
                if (e.getModifiers().contains(Modifier.ABSTRACT)) {
209
                    throw new LayerGenerationException(clazz + " must not be abstract", e);
210
                }
211
                {
212
                    boolean hasDefaultCtor = false;
213
                    for (ExecutableElement constructor : ElementFilter.constructorsIn(e.getEnclosedElements())) {
214
                        if (constructor.getParameters().isEmpty()) {
215
                            hasDefaultCtor = true;
216
                            break;
217
                        }
218
                    }
219
                    if (!hasDefaultCtor) {
220
                        throw new LayerGenerationException(clazz + " must have a no-argument constructor", e);
221
                    }
222
                }
223
                if (typeMirror != null && !processingEnv.getTypeUtils().isAssignable(e.asType(), typeMirror)) {
224
                    throw new LayerGenerationException(clazz + " is not assignable to " + typeMirror, e);
225
                }
226
                return new String[] {clazz, null};
227
            }
228
            case METHOD: {
229
                String clazz = processingEnv.getElementUtils().getBinaryName((TypeElement) e.getEnclosingElement()).toString();
230
                String method = e.getSimpleName().toString();
231
                if (!e.getModifiers().contains(Modifier.STATIC)) {
232
                    throw new LayerGenerationException(clazz + "." + method + " must be static", e);
233
                }
234
                if (!((ExecutableElement) e).getParameters().isEmpty()) {
235
                    throw new LayerGenerationException(clazz + "." + method + " must not take arguments", e);
236
                }
237
                if (typeMirror != null && !processingEnv.getTypeUtils().isAssignable(((ExecutableElement) e).getReturnType(), typeMirror)) {
238
                    throw new LayerGenerationException(clazz + "." + method + " is not assignable to " + typeMirror, e);
239
                }
240
                return new String[] {clazz, method};
241
            }
242
            default:
243
                throw new IllegalArgumentException("Annotated element is not loadable as an instance: " + e);
244
        }
245
    }
246
}
(-)a/settings/src/org/netbeans/modules/settings/convertors/XMLPropertiesConvertor.java (-4 / +7 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);
(-)a/settings/test/unit/src/org/netbeans/modules/settings/convertors/XMLPropertiesConvertorAnnotationTest.java (+98 lines)
Line 0 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
56
/** Checks usage of annotation to assign XML properties convertor.
57
 *
58
 * @author Jaroslav Tulach
59
 */
60
public final class XMLPropertiesConvertorAnnotationTest extends NbTestCase {
61
    /** Creates a new instance of XMLPropertiesConvertorTest */
62
    public XMLPropertiesConvertorAnnotationTest(String name) {
63
        super(name);
64
    }
65
    
66
    public void testReadWrite() throws Exception {
67
        FileObject dtdFO = Repository.getDefault().getDefaultFileSystem().
68
            findResource("/xml/lookups/NetBeans_org_netbeans_modules_settings_xtest/DTD_XML_FooSetting_2_0.instance");
69
        assertNotNull("Provider not found", dtdFO);
70
        Convertor c = XMLPropertiesConvertor.create(dtdFO);
71
        AnnoFoo foo = new AnnoFoo();
72
        foo.setProperty1("xxx");
73
        CharArrayWriter caw = new CharArrayWriter(1024);
74
        c.write(caw, foo);
75
        caw.flush();
76
        caw.close();
77
        CharArrayReader car = new CharArrayReader(caw.toCharArray());
78
        Object obj = c.read(car);
79
        assertEquals(foo, obj);
80
        assertEquals("HooFoo is the class", HooFoo.class, obj.getClass());
81
    }
82
83
    @ConvertAsProperties(
84
        dtd="-//NetBeans org.netbeans.modules.settings.xtest//DTD XML FooSetting 2.0//EN"
85
    )
86
    public static class AnnoFoo extends FooSetting {
87
        public Object readProperties(Properties p) {
88
            HooFoo n = new HooFoo();
89
            n.setProperty1(p.getProperty("p1"));
90
            return n;
91
        }
92
        public void writeProperties(Properties p) {
93
            p.setProperty("p1", this.getProperty1());
94
        }
95
    }
96
    public static class HooFoo extends AnnoFoo {
97
    }
98
}
(-)a/settings/test/unit/src/org/netbeans/modules/settings/convertors/XMLPropertiesConvertorTest.java (-4 lines)
Lines 44-58 Link Here
44
import java.io.*;
44
import java.io.*;
45
45
46
import org.netbeans.junit.NbTestCase;
46
import org.netbeans.junit.NbTestCase;
47
import org.netbeans.junit.NbTestSuite;
48
47
49
import junit.textui.TestRunner;
50
48
51
import org.netbeans.modules.settings.convertors.FooSetting;
52
import org.netbeans.spi.settings.Convertor;
49
import org.netbeans.spi.settings.Convertor;
53
import org.netbeans.spi.settings.Saver;
50
import org.netbeans.spi.settings.Saver;
54
import org.openide.cookies.InstanceCookie;
51
import org.openide.cookies.InstanceCookie;
55
import org.openide.cookies.SaveCookie;
56
import org.openide.filesystems.FileLock;
52
import org.openide.filesystems.FileLock;
57
53
58
import org.openide.filesystems.FileObject;
54
import org.openide.filesystems.FileObject;

Return to bug 155962