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 252016
Collapse All | Expand All

(-)a/api.templates/apichanges.xml (+16 lines)
Lines 54-59 Link Here
54
<!-- ACTUAL CHANGES BEGIN HERE: -->
54
<!-- ACTUAL CHANGES BEGIN HERE: -->
55
55
56
  <changes>
56
  <changes>
57
      <change id="composition">
58
          <api name="templates"/>
59
          <summary>Support for composition</summary>
60
          <version major="1" minor="5"/>
61
          <date year="2015" month="4" day="23"/>
62
          <author login="sdedic"/>
63
          <compatibility addition="yes" binary="compatible" source="compatible"/>
64
          <description>
65
              TemplateHandler may need to create additional files, using the same parameters for creation as a base.
66
              Attribute providers may need to be processed in a custom way, which requires to create and manage CreateDescriptor
67
              by the client. This change allows to clone information from CreateDescriptor into an independent FileBuilder, and
68
              to create a Descriptor out of a Builder.
69
          </description>
70
          <class package="org.netbeans.api.templates" name="FileBuilder"/>
71
          <issue number=""/>
72
      </change>
57
      <change id="techids">
73
      <change id="techids">
58
          <api name="templates"/>
74
          <api name="templates"/>
59
          <summary>Support for Technology Ids</summary>
75
          <summary>Support for Technology Ids</summary>
(-)a/api.templates/manifest.mf (-1 / +1 lines)
Lines 2-6 Link Here
2
AutoUpdate-Show-In-Client: false
2
AutoUpdate-Show-In-Client: false
3
OpenIDE-Module: org.netbeans.api.templates
3
OpenIDE-Module: org.netbeans.api.templates
4
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/templates/Bundle.properties
4
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/templates/Bundle.properties
5
OpenIDE-Module-Specification-Version: 1.4
5
OpenIDE-Module-Specification-Version: 1.5
6
OpenIDE-Module-Recommends: org.netbeans.templates.IndentEngine
6
OpenIDE-Module-Recommends: org.netbeans.templates.IndentEngine
(-)a/api.templates/src/org/netbeans/api/templates/CreateFromTemplateImpl.java (-2 / +7 lines)
Lines 92-97 Link Here
92
        return impl.build();
92
        return impl.build();
93
    }
93
    }
94
    
94
    
95
    static void collectAttributes(FileBuilder flb) {
96
        CreateFromTemplateImpl impl = new CreateFromTemplateImpl(flb);
97
        flb.withParameters(impl.findTemplateParameters());
98
    }
99
    
95
    List<FileObject> build() throws IOException {
100
    List<FileObject> build() throws IOException {
96
        // side effects: replaces the map in CreateDescriptor
101
        // side effects: replaces the map in CreateDescriptor
97
        try {
102
        try {
Lines 108-114 Link Here
108
            }
113
            }
109
            // also modifies desc.getParameters, result not needed.
114
            // also modifies desc.getParameters, result not needed.
110
            findTemplateParameters();
115
            findTemplateParameters();
111
            computeEffectiveName();
116
            computeEffectiveName(desc);
112
117
113
            List<FileObject> pf = null;
118
            List<FileObject> pf = null;
114
            for (CreateFromTemplateHandler h : Lookup.getDefault().lookupAll(CreateFromTemplateHandler.class)) {
119
            for (CreateFromTemplateHandler h : Lookup.getDefault().lookupAll(CreateFromTemplateHandler.class)) {
Lines 129-135 Link Here
129
        }
134
        }
130
    }
135
    }
131
    
136
    
132
    private void computeEffectiveName() {
137
    /* package private */ static void computeEffectiveName(CreateDescriptor desc) {
133
        String name = desc.getName();
138
        String name = desc.getName();
134
        if (name == null) {
139
        if (name == null) {
135
            // name is not set - try to check parameters, if some template attribute handler
140
            // name is not set - try to check parameters, if some template attribute handler
(-)a/api.templates/src/org/netbeans/api/templates/FileBuilder.java (+47 lines)
Lines 56-61 Link Here
56
import org.openide.filesystems.FileObject;
56
import org.openide.filesystems.FileObject;
57
import org.openide.filesystems.FileUtil;
57
import org.openide.filesystems.FileUtil;
58
import org.openide.util.MapFormat;
58
import org.openide.util.MapFormat;
59
import org.openide.util.Parameters;
59
60
60
/**
61
/**
61
 * Fluent interface for file creation. The Builder is first parametrized. After
62
 * Fluent interface for file creation. The Builder is first parametrized. After
Lines 101-106 Link Here
101
    }
102
    }
102
    
103
    
103
    /**
104
    /**
105
     * Creates a Builder based on the CreateDescriptor. The FileBuilder inherits 
106
     * all parameters of the original {@link CreateDescriptor}. The client may change the attributes.
107
     * The method may be useful when creating secondary files; for example target and all attributes
108
     * are retained. During {@link #build()}, attributes may be redefined as needed for the 
109
     * additional file, just like in normal Builder operation.
110
     * <p/>
111
     * The new FileBuilder instance is completely indepenent of the original Descriptor. If the CreateDescriptor
112
     * supports additional properties in the future, using this method guarantees that they will be
113
     * transferred to the FileBuilder copy.
114
     * 
115
     * @param desc the original descriptor
116
     * @return new FileBuilder
117
     * @since 1.5
118
     */
119
    public static @NonNull FileBuilder fromDescriptor(@NonNull CreateDescriptor desc) {
120
        Parameters.notNull("desc", desc);
121
        return new FileBuilder(desc.getTemplate(), desc.getTarget()).
122
                name(desc.getProposedName()).
123
                useLocale(desc.getLocale()).
124
                withParameters(desc.getParameters());
125
    }
126
    
127
    /**
104
     * Creates a new FileBuilder for a specific template and target folder.
128
     * Creates a new FileBuilder for a specific template and target folder.
105
     * @param template the template to use.
129
     * @param template the template to use.
106
     * @param target the target folder; must already exist.
130
     * @param target the target folder; must already exist.
Lines 230-235 Link Here
230
        return descriptor;
254
        return descriptor;
231
    }
255
    }
232
    
256
    
257
    /**
258
     * Creates a descriptor from the current Builder's state. 
259
     * If `collectAttributes' is false, the descriptor
260
     * will have no additional parameters set from {@link CreateFromTemplateAttributes} providers;
261
     * the caller must process the providers, if it wishes to get additional attributes.
262
     * The Descriptor can be used to collect information from attribute providers or manually
263
     * trigger file creation in template handler.
264
     * <p/>
265
     * The operation changes the FileBuilder state.
266
     * 
267
     * @param collectAttributes if true, attribute providers are asked to add their attributes
268
     * to the builder/descriptor.
269
     * @return descriptor
270
     * @since 1.5
271
     */
272
    public @NonNull CreateDescriptor createDescriptor(boolean collectAttributes) {
273
        if (collectAttributes) {
274
            CreateFromTemplateImpl.collectAttributes(this);
275
        }
276
        CreateFromTemplateImpl.computeEffectiveName(descriptor);
277
        return descriptor;
278
    }
279
    
233
    private final CreateDescriptor descriptor;
280
    private final CreateDescriptor descriptor;
234
    
281
    
235
    @SuppressWarnings("PackageVisibleField")
282
    @SuppressWarnings("PackageVisibleField")
(-)a/projectuiapi/nbproject/project.xml (-1 / +1 lines)
Lines 80-86 Link Here
80
                    <build-prerequisite/>
80
                    <build-prerequisite/>
81
                    <compile-dependency/>
81
                    <compile-dependency/>
82
                    <run-dependency>
82
                    <run-dependency>
83
                        <specification-version>1.3</specification-version>
83
                        <specification-version>1.5</specification-version>
84
                    </run-dependency>
84
                    </run-dependency>
85
                </dependency>
85
                </dependency>
86
                <dependency>
86
                <dependency>
(-)a/projectuiapi/src/org/netbeans/modules/project/uiapi/ProjectTemplateAttributesProvider.java (-8 / +10 lines)
Lines 45-50 Link Here
45
package org.netbeans.modules.project.uiapi;
45
package org.netbeans.modules.project.uiapi;
46
46
47
import java.io.IOException;
47
import java.io.IOException;
48
import java.lang.reflect.InvocationTargetException;
49
import java.lang.reflect.Method;
48
import java.net.URI;
50
import java.net.URI;
49
import java.nio.charset.Charset;
51
import java.nio.charset.Charset;
50
import java.util.Collection;
52
import java.util.Collection;
Lines 56-61 Link Here
56
import org.netbeans.api.queries.FileEncodingQuery;
58
import org.netbeans.api.queries.FileEncodingQuery;
57
import org.netbeans.api.templates.CreateDescriptor;
59
import org.netbeans.api.templates.CreateDescriptor;
58
import org.netbeans.api.templates.CreateFromTemplateAttributes;
60
import org.netbeans.api.templates.CreateFromTemplateAttributes;
61
import org.netbeans.api.templates.FileBuilder;
59
import org.openide.filesystems.FileObject;
62
import org.openide.filesystems.FileObject;
60
import org.openide.filesystems.FileUtil;
63
import org.openide.filesystems.FileUtil;
61
import org.openide.loaders.CreateFromTemplateAttributesProvider;
64
import org.openide.loaders.CreateFromTemplateAttributesProvider;
Lines 84-90 Link Here
84
        FileObject targetF = desc.getTarget();
87
        FileObject targetF = desc.getTarget();
85
        String name = desc.getProposedName();
88
        String name = desc.getProposedName();
86
        Project prj = FileOwnerQuery.getOwner(targetF);
89
        Project prj = FileOwnerQuery.getOwner(targetF);
87
        Map<String, Object> all = null;
90
        Map<String, Object> all = new HashMap();
88
        if (prj != null) {
91
        if (prj != null) {
89
            // call old providers
92
            // call old providers
90
            Collection<? extends CreateFromTemplateAttributesProvider> oldProvs = prj.getLookup().lookupAll(CreateFromTemplateAttributesProvider.class);
93
            Collection<? extends CreateFromTemplateAttributesProvider> oldProvs = prj.getLookup().lookupAll(CreateFromTemplateAttributesProvider.class);
Lines 97-105 Link Here
97
                        for (CreateFromTemplateAttributesProvider attrs : oldProvs) {
100
                        for (CreateFromTemplateAttributesProvider attrs : oldProvs) {
98
                            Map<String, ? extends Object> m = attrs.attributesFor(template, target, name);
101
                            Map<String, ? extends Object> m = attrs.attributesFor(template, target, name);
99
                            if (m != null) {
102
                            if (m != null) {
100
                                if (all == null) {
101
                                    all = new HashMap<String, Object>();
102
                                }
103
                                all.putAll(m);
103
                                all.putAll(m);
104
                            }
104
                            }
105
                        }
105
                        }
Lines 110-121 Link Here
110
                }
110
                }
111
            }
111
            }
112
            // call new providers last, so they can override anything old providers could screw up.
112
            // call new providers last, so they can override anything old providers could screw up.
113
            // new providers should get all attributes collected from previous (new-style) CFTAs incl. attributes provided
114
            // by [deprecated] CFTAPs accumulated above.
115
            FileBuilder bld = FileBuilder.fromDescriptor(desc);
116
            // temporary:
113
            for (CreateFromTemplateAttributes attrs : prj.getLookup().lookupAll(CreateFromTemplateAttributes.class)) {
117
            for (CreateFromTemplateAttributes attrs : prj.getLookup().lookupAll(CreateFromTemplateAttributes.class)) {
114
                Map<String, ? extends Object> m = attrs.attributesFor(desc);
118
                CreateDescriptor childDesc = bld.withParameters(all).createDescriptor(false);
119
                Map<String, ? extends Object> m = attrs.attributesFor(childDesc);
115
                if (m != null) {
120
                if (m != null) {
116
                    if (all == null) {
117
                        all = new HashMap<String, Object>();
118
                    }
119
                    all.putAll(m);
121
                    all.putAll(m);
120
                }
122
                }
121
            }
123
            }
(-)a/projectuiapi/test/unit/src/org/netbeans/modules/project/uiapi/ProjectTemplateAttributesProviderTest.java (-1 / +123 lines)
Lines 42-57 Link Here
42
42
43
package org.netbeans.modules.project.uiapi;
43
package org.netbeans.modules.project.uiapi;
44
44
45
import java.io.IOException;
45
import java.nio.charset.Charset;
46
import java.nio.charset.Charset;
46
import java.util.Collections;
47
import java.util.Collections;
47
import java.util.HashMap;
48
import java.util.HashMap;
48
import java.util.Map;
49
import java.util.Map;
50
import org.netbeans.api.project.Project;
51
import org.netbeans.api.project.ProjectManager;
49
import org.netbeans.api.project.TestUtil;
52
import org.netbeans.api.project.TestUtil;
50
import org.netbeans.api.queries.FileEncodingQuery;
53
import org.netbeans.api.queries.FileEncodingQuery;
54
import org.netbeans.api.templates.CreateDescriptor;
55
import org.netbeans.api.templates.CreateFromTemplateAttributes;
56
import org.netbeans.api.templates.FileBuilder;
51
import org.netbeans.junit.NbTestCase;
57
import org.netbeans.junit.NbTestCase;
58
import org.netbeans.spi.project.ProjectFactory;
59
import org.netbeans.spi.project.ProjectState;
52
import org.netbeans.spi.queries.FileEncodingQueryImplementation;
60
import org.netbeans.spi.queries.FileEncodingQueryImplementation;
53
import org.openide.filesystems.FileObject;
61
import org.openide.filesystems.FileObject;
62
import org.openide.filesystems.FileUtil;
63
import org.openide.loaders.CreateFromTemplateAttributesProvider;
64
import org.openide.loaders.DataFolder;
65
import org.openide.loaders.DataObject;
66
import org.openide.util.Lookup;
54
import org.openide.util.NbCollections;
67
import org.openide.util.NbCollections;
68
import org.openide.util.lookup.Lookups;
55
import org.openide.util.test.MockLookup;
69
import org.openide.util.test.MockLookup;
56
70
57
/**
71
/**
Lines 62-67 Link Here
62
76
63
    private FileObject scratch;
77
    private FileObject scratch;
64
    private FileObject folder;
78
    private FileObject folder;
79
    private FileObject projdir;
65
80
66
    public ProjectTemplateAttributesProviderTest(String testName) {
81
    public ProjectTemplateAttributesProviderTest(String testName) {
67
        super(testName);
82
        super(testName);
Lines 72-81 Link Here
72
        super.setUp();
87
        super.setUp();
73
        scratch = TestUtil.makeScratchDir(this);
88
        scratch = TestUtil.makeScratchDir(this);
74
        folder = scratch.createFolder("folder");
89
        folder = scratch.createFolder("folder");
75
        MockLookup.setInstances(new FEQImpl());
90
91
        projdir = scratch.createFolder("proj");
92
        
93
        createProject(projdir);
94
95
        MockLookup.setInstances(new FEQImpl(), new TestProjectFactory());
76
        assertEquals(FEQImpl.ENCODING, FileEncodingQuery.getEncoding(folder).name());
96
        assertEquals(FEQImpl.ENCODING, FileEncodingQuery.getEncoding(folder).name());
77
    }
97
    }
78
98
99
    private void createProject(FileObject projdir) throws Exception {
100
        TestUtil.createFileFromContent(ProjectTemplateAttributesProviderTest.class.getResource("data/test.txt"), projdir, "nbproject/test.txt");
101
        TestUtil.createFileFromContent(ProjectTemplateAttributesProviderTest.class.getResource("data/test.txt"), projdir, "src/test/test.txt");
102
    }
103
    
104
    /**
105
     * Checks that the attribute providers execute in the correct order and see other provider's data.
106
     * Legacy providers should execute first. New providers should execute after that. Each new-style
107
     * provider should see all attributes defined by previous providers (legacy or new).
108
     * 
109
     * @throws Exception 
110
     */
111
    public void testProjectAttributeProviders() throws Exception {
112
        Project prj = ProjectManager.getDefault().findProject(projdir);
113
        FileObject folder = projdir.getFileObject("nbproject");
114
        FileObject template = FileUtil.toFileObject(getDataDir()).getFileObject("file.txt");
115
        Map<String, Object> init = new HashMap();
116
        init.put("mama", "se raduje");
117
        FileObject result = FileBuilder.createFromTemplate(template, folder, "honza", init, FileBuilder.Mode.FORMAT);
118
        
119
        assertEquals(
120
                "Jedna, 2, Honza jde. Nese 2 pytle s brouky. Mama se raduje, ze bude pect vdolky.\n",
121
                result.asText());
122
    }
123
    
124
79
    public void testCheckProjectAttrs() throws Exception {
125
    public void testCheckProjectAttrs() throws Exception {
80
        Map<String, ? extends Object> checked = ProjectTemplateAttributesProvider.checkProjectAttrs(null, folder);
126
        Map<String, ? extends Object> checked = ProjectTemplateAttributesProvider.checkProjectAttrs(null, folder);
81
        assertAttribute("default", checked, "license");
127
        assertAttribute("default", checked, "license");
Lines 128-131 Link Here
128
            return null;
174
            return null;
129
        }
175
        }
130
    }
176
    }
177
    
178
    private static final class AttrProv1 implements CreateFromTemplateAttributes {
179
180
        @Override
181
        public Map<String, ?> attributesFor(CreateDescriptor desc) {
182
            Map<String, Object> m = new HashMap<String, Object>();
183
            m.put("jedna", 2); // used by Prov2
184
            m.put("dve", "Honza jde");
185
            return m;
186
        }
187
        
188
    }
189
    
190
    private static final class AttrProv2 implements CreateFromTemplateAttributes {
191
        @Override
192
        public Map<String, ?> attributesFor(CreateDescriptor desc) {
193
            String s = desc.getValue("pytel");
194
            s += " brouky";
195
            Map m = new HashMap();
196
            m.put("pytel", s); // replace /append to legacy-provided value
197
            m.put("nese", desc.getValue("jedna")); // copy previous value
198
            return m;
199
        }
200
    }
201
    
202
    private static final class AttrProvLegacy implements CreateFromTemplateAttributesProvider {
203
        @Override
204
        public Map<String, ?> attributesFor(DataObject template, DataFolder target, String name) {
205
            Map m = new HashMap();
206
            m.put("pytel", "s"); // appended by Prov2
207
            m.put("bude", "bude pect vdolky");
208
            return m;
209
        }
210
    }
211
212
    private static final class TestProject implements Project {
213
        
214
        private final Lookup l;
215
        private final FileObject projectDirectory;
216
        
217
        TestProject(FileObject projectDirectory) throws IOException {
218
            l = Lookups.fixed(new AttrProv1(), new AttrProv2(), new AttrProvLegacy());
219
            this.projectDirectory = projectDirectory;
220
        }
221
        
222
        public FileObject getProjectDirectory() {
223
            return projectDirectory;
224
        }
225
        
226
        public Lookup getLookup() {
227
            return l;
228
        }
229
        
230
        public String toString() {
231
            return "TestAntBasedProject[" + getProjectDirectory() + "]";
232
        }
233
        
234
    }
235
    
236
    public static class TestProjectFactory implements ProjectFactory {
237
        
238
        public boolean isProject(FileObject projectDirectory) {
239
            return projectDirectory.getFileObject("nbproject") != null;
240
        }
241
        
242
        public Project loadProject(FileObject projectDirectory, ProjectState state) throws IOException {
243
            if (isProject(projectDirectory))
244
                return new TestProject(projectDirectory);
245
            
246
            return null;
247
        }
248
        
249
        public void saveProject(Project project) throws IOException, ClassCastException {
250
        }
251
        
252
    }
131
}
253
}

Return to bug 252016