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

(-)a/api.templates/arch.xml (+432 lines)
Line 0 Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<!DOCTYPE api-answers PUBLIC "-//NetBeans//DTD Arch Answers//EN" "../nbbuild/antsrc/org/netbeans/nbbuild/Arch.dtd" [
3
  <!ENTITY api-questions SYSTEM "../nbbuild/antsrc/org/netbeans/nbbuild/Arch-api-questions.xml">
4
]>
5
6
<api-answers
7
  question-version="1.29"
8
  author="sdedic@netbeans.org"
9
>
10
11
  &api-questions;
12
13
 <answer id="arch-overall">
14
  <p>
15
      API allows to create new files based on templates. Scripting engines can be specified for
16
      processing the template, or custom Handlers may be registered to process certain templates.
17
  </p>
18
  <p>
19
      A template can use places substituable with parameter values; certain well-known parameters are 
20
      predefined, if the caller does not provide its custom values.
21
  </p>
22
 </answer>
23
 <answer id="arch-quality">
24
  <p>
25
   The feature will be fully covered by unit tests.
26
  </p>
27
 </answer>
28
 <answer id="arch-time">
29
  <p>
30
   October 2014
31
  </p>
32
 </answer>
33
34
35
36
<!--
37
        <question id="arch-usecases" when="init">
38
            <hint>
39
                Content of this answer will be displayed as part of page at
40
                http://www.netbeans.org/download/dev/javadoc/usecases.html 
41
                You can use tags &lt;usecase name="name&gt; regular html description &lt;/usecase&gt;
42
                and if you want to use an URL you can prefix if with @TOP@ to begin
43
                at the root of your javadoc
44
            </hint>
45
        
46
            Describe the main <a href="http://wiki.netbeans.org/API_Design#The_Importance_of_Being_Use_Case_Oriented">
47
            use cases</a> of the new API. Who will use it under
48
            what circumstances? What kind of code would typically need to be written
49
            to use the module?
50
        </question>
51
-->
52
 <answer id="arch-usecases">
53
     <usecase id="template" name="Use boilerplates">
54
         <p>
55
             An existing file can be used as a boilerplate for creation of a new file.
56
             The boiler plate can contain necessary skeleton, comments, content. As the
57
             boilerplate resides on config filesystem, it is also customizable by the user
58
             and the user can eventually develop custom templates.
59
         </p>
60
         <p>
61
             In previous NetBeans versions, templating system was built into 
62
             <api name="DataSystemsAPI" category="official" group="java" type="export" 
63
                url="@org-openide-loaders@/index.html"/>.
64
         </p>
65
     </usecase>
66
     <usecase id="templateHandler" name="Custom template handlers">
67
        <p>
68
            Often many people require ability to create a "clever" template - e.g.
69
            write piece of simple text and at the time of its 
70
            <a href="@TOP@/org/netbeans/api/templates/TemplateUtils.html#createFromTemplate(org.openide.filesystems.FileObject, org.openide.filesystems.FileObject, java.lang.String, java.util.Map, org.netbeans.api.templates.FileBuilder.Mode)">
71
                processing
72
            </a> 
73
            do some advanced changes to it using either 
74
            <a name="script">scripting or templating</a> languages.
75
        </p>
76
        <p>
77
            This traditionally used to be a bit complicated task (hacking into DataObject implementation), however since 
78
            version 6.1 there are interface in 
79
            <api name="org.openide.loaders.CreateFromTemplateHandler" category="deprecated" group="lookup" type="export"
80
                 url="@org-openide-loaders@/org/openide/loaders/CreateFromTemplateHandler.html">
81
                DataSystem API
82
            </api>
83
            and finally
84
            <api name="org.netbeans.api.templates.CreateFromTemplateHandler" category="official" group="lookup" type="export"
85
             url="@TOP@/org/netbeans/api/templates/CreateFromTemplateHandler.html">
86
                that can be registered as a services in a lookup and it is reponsible
87
                for handling the whole copy of the template file(s) to the destination
88
                folder.
89
            </api>
90
        </p>
91
     </usecase>
92
     <usecase id="templateAttributes" name="Custom attributes for processing">
93
         <p>
94
            Runtime or project-related values may be supplied by 
95
           <api name="org.openide.loaders.CreateFromTemplateAttributes" category="official" group="lookup" type="export"
96
           url="@TOP@/org/netbeans/api/templates/CreateFromTemplateAttributes.html">
97
               that can be registered as a services in a lookup and it is reponsible
98
               for providing "hints" - e.g. map mapping strings to various objects.
99
           </api> and these interfaces allow anyone to extend the behaviour during
100
           creation of new files.
101
         </p>
102
         <p>
103
             The <a href="@TOP@/org/netbeans/api/templates/CreateFromTemplateAttributes.html">CreateFromTemplateAttribute</a> implementation
104
             knows which template is being used, where the outcome should be placed, so it can derive appropriate values for both 
105
             the template and the target location.
106
         </p>
107
     </usecase>
108
     <usecase id="script" name="Using Scripting and Templating Languages" >
109
        <p>
110
        There is a built in support for scripting languages in
111
        the standard NetBeans IDE. If a template is annotated with
112
        <api name="javax.script.ScriptEngine" category="official" group="property" type="export">
113
            a property that can be associated to templates that either should
114
            return real instance of <code>ScriptEngine</code> interface or
115
            a <code>String</code> name of the engine that is then used to
116
            search for it in the <code>javax.script.ScriptEngineManager</code>.
117
            Usually the <a href="http://freemarker.sourceforge.net/">freemarker</a> engine is the one that is 
118
            supported by the NetBeans IDE - if your module wants to use it
119
            then include a token dependency <code>OpenIDE-Module-Needs: javax.script.ScriptEngine.freemarker</code>
120
            in your manifest file (also accessible through project customizer GUI)
121
            to indicate to the system that you need it.
122
        </api>
123
        then the scripting engine is then used to process the template and
124
        generate the output file. While running the engine one can rely
125
        on few predefined properties:
126
        </p>
127
128
        <ul>
129
            <li><api name="name" category="stable" group="property" type="export"> contains the name of the <a href="@org-openide-loaders@/org/openide/loaders/DataObject.html">DataObject</a> that is being created</api></li>
130
            <li><api name="user" category="stable" group="property" type="export"> contains the name the user</api></li>
131
            <li><api name="nameAndExt" category="stable" group="property" type="export"> contains the name and extension of the file that is being created</api></li>
132
            <li><api name="date" category="stable" group="property" type="export"> contains <code>String</code> representing the current day like <code>23. 3. 2007</code></api></li>
133
            <li><api name="time" category="stable" group="property" type="export"> contains <code>String</code> the current time like <code>17:18:30</code></api></li>
134
            <li><api name="dateTime" category="stable" group="property" type="export"> contains <code>java.util.Date</code> representing current data and time like</api></li>
135
            <li><api name="encoding" category="stable" group="property" type="export"> contains <code>String</code> the file encoding of the template instance</api></li>
136
        </ul>
137
        
138
        <p>
139
        Other properties can indeed be provided by
140
        <a href="@TOP@/org/netbeans/api/templates/CreateFromTemplateAttributes.html">CreateFromTemplateAttributes</a>s.
141
        After processing, the output is also sent to appropriate
142
        <code>org.openide.text.IndentEngine</code> associated
143
        with the mime type of the template, for formating.
144
        </p>
145
146
        <p style="margin-left: 0.2in; margin-right: 0.2in; margin-top: 0.2in; margin-bottom: 0.2in; border: 1.00pt solid #9999cc; padding: 0.1in; color: #666699">
147
            <b>Smart Templating Quick How-To</b>
148
            <br/>
149
            
150
            First of all create a file in your module layer located somewhere
151
            under the <code>Templates/</code> folder. Make it a template by
152
            adding &lt;attr name="template" boolvalue="true"/&gt;. Associate
153
            this template with a scripting language, for example by
154
            &lt;attr name="javax.script.ScriptEngine" stringvalue="freemarker"/&gt;.
155
            Now make sure that the scripting language integration is also available
156
            by requesting a token in standard format, for freemarker just put
157
            <code>OpenIDE-Module-Needs: javax.script.ScriptEngine.freemarker</code>
158
            in your manifest. This tells the NetBeans module system that a 
159
            module providing integration with such scripting engine has to be 
160
            enabled. Now you can use regular script language tags inside of
161
            your template file. When you write your <code>instantiate</code>
162
            method in your wizard, you can create a Map&lt;String,Object&gt; and
163
            fill it with parameters collected from your wizard and then pass it 
164
            to
165
            <a href="@org-openide-loaders@/org/openide/loaders/DataObject.html#createFromTemplate(org.openide.loaders.DataFolder,%20java.lang.String,%20java.util.Map)">                
166
                createFromTemplate(targetFolder, targetName, mapWithParameters)
167
            </a>. This will invoke the scripting language and make the 
168
            <code>mapWithParameters</code> values available to it. Beyond this 
169
            there is few standard parameters predefined including <code>name</code>, <code>user</code>, <code>date</code>, <code>time</code>, etc.
170
            and also additional parameters are collected from all registered
171
            <a href="@org-openide-loaders@/org/openide/loaders/CreateFromTemplateAttributesProvider.html">CreateFromTemplateAttributesProvider</a>s.
172
        </p>
173
        
174
     </usecase>
175
    <usecase id="file-sets" name="Create sets of files" >
176
        <p>
177
            A <a href="@TOP@/org/netbeans/api/templates/CreateFromTemplateHandler.html">CreateFromTemplateHandler</a>
178
            should be able to create multiple files, one of them <i>important</i> so it will open after user 
179
            initiates the creation action. The template of set of related files may be represented by a folder with
180
            a handler attached, and the operation deploys multiple files in the target directory.
181
        </p>
182
    </usecase>
183
 </answer>
184
 <answer id="arch-what">
185
  <p>
186
   This utility standardizes the process to use files as blueprints to create new files.
187
  </p>
188
 </answer>
189
 <answer id="arch-where">
190
  <defaultanswer generate='here' />
191
 </answer>
192
 <answer id="compat-deprecation">
193
  <p>
194
   This module replaces some implementation in DataSystem APIs so the implementation
195
    is usable even without DataSystems API itself. DataSystems API will use this
196
    library.
197
  </p>
198
 </answer>
199
 <answer id="compat-i18n">
200
  <p>
201
   Yes.
202
  </p>
203
 </answer>
204
 <answer id="compat-standards">
205
  <p>
206
   No.
207
  </p>
208
 </answer>
209
 <answer id="compat-version">
210
  <p>
211
   Yes.
212
  </p>
213
 </answer>
214
 <answer id="dep-jre">
215
  <p>
216
   Requires JRE 7, for implementation reasons (AutoCloseable).
217
  </p>
218
 </answer>
219
 <answer id="dep-jrejdk">
220
  <p>
221
   JRE
222
  </p>
223
 </answer>
224
 <answer id="dep-nb">
225
  <defaultanswer generate='here' />
226
 </answer>
227
 <answer id="dep-non-nb">
228
  <p>
229
   None.
230
  </p>
231
 </answer>
232
 <answer id="dep-platform">
233
  <p>
234
   No native platform dependencies.
235
  </p>
236
 </answer>
237
 <answer id="deploy-dependencies">
238
  <p>
239
   No specific deploy dependencies.
240
  </p>
241
 </answer>
242
 <answer id="deploy-jar">
243
  <p>
244
   JARs only.
245
  </p>
246
 </answer>
247
 <answer id="deploy-nbm">
248
  <p>
249
   Yes.
250
  </p>
251
 </answer>
252
 <answer id="deploy-packages">
253
  <p>
254
   Yes, except API.
255
  </p>
256
 </answer>
257
 <answer id="deploy-shared">
258
  <p>
259
   Anywhere.
260
  </p>
261
 </answer>
262
 <answer id="exec-ant-tasks">
263
  <p>
264
   No.
265
  </p>
266
 </answer>
267
 <answer id="exec-classloader">
268
  <p>
269
   No.
270
  </p>
271
 </answer>
272
 <answer id="exec-component">
273
  <p>
274
   No.
275
  </p>
276
 </answer>
277
 <answer id="exec-introspection">
278
  <p>
279
   No.
280
  </p>
281
 </answer>
282
 <answer id="exec-privateaccess">
283
  <p>
284
   No.
285
  </p>
286
 </answer>
287
 <answer id="exec-process">
288
  <p>
289
   No.
290
  </p>
291
 </answer>
292
 <answer id="exec-property">
293
  <p>
294
    <api name="org.netbeans.api.templates.IndentEngine" category="friend" group="property" type="export">
295
    A special ScriptEngine type is required to perform indentation on the produced sources.
296
    The ScriptEngine must provide a name "<code>org.netbeans.api.templates.IndentEngine</code>". 
297
    The only attribute property passed to the ScriptContext is <code>mimeType</code> of the 
298
    text being formatted.
299
    </api>
300
  </p>
301
 </answer>
302
 <answer id="exec-reflection">
303
  <p>
304
   No.
305
  </p>
306
 </answer>
307
 <answer id="exec-threading">
308
  <p>
309
   Yes.
310
  </p>
311
 </answer>
312
 <answer id="format-clipboard">
313
  <p>
314
   None.
315
  </p>
316
 </answer>
317
 <answer id="format-dnd">
318
  <p>
319
   None.
320
  </p>
321
 </answer>
322
 <answer id="format-types">
323
  <p>
324
   None.
325
  </p>
326
 </answer>
327
 <answer id="lookup-lookup">
328
  <p>
329
      Yes, looks up <a href="@TOP@/org/netbeans/api/templates/CreateFromTemplateAttributes.html">CreateFromTemplateAttributes</a>
330
      and <a href="@TOP@/org/netbeans/api/templates/CreateFromTemplateHandler.html">CreateFromTemplateHandler</a>.
331
  </p>
332
 </answer>
333
 <answer id="lookup-register">
334
  <p>
335
      Registers handler, which integrates scripting engines using <code>javax.script</code> API. Provides an annotation
336
      processor, so it is easy to register - see 
337
      <a href="@TOP@/org/netbeans/api/templates/TemplateRegistration.html">TemplateRegistration</a> annotation.
338
  </p>
339
 </answer>
340
 <answer id="lookup-remove">
341
  <p>
342
   No.
343
  </p>
344
 </answer>
345
 <answer id="perf-exit">
346
  <p>
347
   No.
348
  </p>
349
 </answer>
350
 <answer id="perf-huge_dialogs">
351
  <p>
352
   No UI.
353
  </p>
354
 </answer>
355
 <answer id="perf-limit">
356
  <p>
357
   Files are processed in-memory in documents; practical limits are imposed
358
    by the platform's Document implementation.
359
  </p>
360
 </answer>
361
 <answer id="perf-mem">
362
  <p>
363
   See 'perf-limit'
364
  </p>
365
 </answer>
366
 <answer id="perf-menus">
367
  <p>
368
   No UI.
369
  </p>
370
 </answer>
371
 <answer id="perf-progress">
372
  <p>
373
   No.
374
  </p>
375
 </answer>
376
 <answer id="perf-scale">
377
  <p>
378
   XXX no answer for perf-scale
379
  </p>
380
 </answer>
381
 <answer id="perf-spi">
382
  <p>
383
   No practical enforcement.
384
  </p>
385
 </answer>
386
 <answer id="perf-startup">
387
  <p>
388
   No.
389
  </p>
390
 </answer>
391
 <answer id="perf-wakeup">
392
  <p>
393
   No.
394
  </p>
395
 </answer>
396
 <answer id="resources-file">
397
  <p>
398
   No.
399
  </p>
400
 </answer>
401
 <answer id="resources-layer">
402
  <p>
403
   No.
404
  </p>
405
 </answer>
406
 <answer id="resources-mask">
407
  <p>
408
   No.
409
  </p>
410
 </answer>
411
 <answer id="resources-preferences">
412
  <p>
413
   No.
414
  </p>
415
 </answer>
416
 <answer id="resources-read">
417
  <p>
418
   No.
419
  </p>
420
 </answer>
421
 <answer id="security-grant">
422
  <p>
423
   No.
424
  </p>
425
 </answer>
426
 <answer id="security-policy">
427
  <p>
428
   No.
429
  </p>
430
 </answer>
431
432
</api-answers>
(-)a/api.templates/build.xml (+5 lines)
Line 0 Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<project basedir="." default="netbeans" name="api.templates">
3
    <description>Builds, tests, and runs the project org.netbeans.api.templates</description>
4
    <import file="../nbbuild/templates/projectized.xml"/>
5
</project>
(-)a/api.templates/manifest.mf (+6 lines)
Line 0 Link Here
1
Manifest-Version: 1.0
2
AutoUpdate-Show-In-Client: false
3
OpenIDE-Module: org.netbeans.api.templates
4
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/templates/Bundle.properties
5
OpenIDE-Module-Specification-Version: 1.0
6
OpenIDE-Module-Recommends: org.netbeans.templates.IndentEngine
(-)a/api.templates/nbproject/project.properties (+3 lines)
Line 0 Link Here
1
javac.source=1.7
2
javac.compilerargs=-Xlint -Xlint:-serial
3
javadoc.arch=${basedir}/arch.xml
(-)a/api.templates/nbproject/project.xml (+129 lines)
Line 0 Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<project xmlns="http://www.netbeans.org/ns/project/1">
3
    <type>org.netbeans.modules.apisupport.project</type>
4
    <configuration>
5
        <data xmlns="http://www.netbeans.org/ns/nb-module-project/3">
6
            <code-name-base>org.netbeans.api.templates</code-name-base>
7
            <module-dependencies>
8
                <dependency>
9
                    <code-name-base>org.netbeans.api.annotations.common</code-name-base>
10
                    <build-prerequisite/>
11
                    <compile-dependency/>
12
                    <run-dependency>
13
                        <release-version>1</release-version>
14
                        <specification-version>1.25</specification-version>
15
                    </run-dependency>
16
                </dependency>
17
                <dependency>
18
                    <code-name-base>org.netbeans.modules.nbjunit</code-name-base>
19
                    <build-prerequisite/>
20
                    <compile-dependency/>
21
                    <run-dependency>
22
                        <release-version>1</release-version>
23
                        <specification-version>1.85</specification-version>
24
                    </run-dependency>
25
                </dependency>
26
                <dependency>
27
                    <code-name-base>org.netbeans.modules.queries</code-name-base>
28
                    <build-prerequisite/>
29
                    <compile-dependency/>
30
                    <run-dependency>
31
                        <release-version>1</release-version>
32
                        <specification-version>1.40</specification-version>
33
                    </run-dependency>
34
                </dependency>
35
                <dependency>
36
                    <code-name-base>org.openide.filesystems</code-name-base>
37
                    <build-prerequisite/>
38
                    <compile-dependency/>
39
                    <run-dependency>
40
                        <specification-version>9.1</specification-version>
41
                    </run-dependency>
42
                </dependency>
43
                <dependency>
44
                    <code-name-base>org.openide.util</code-name-base>
45
                    <build-prerequisite/>
46
                    <compile-dependency/>
47
                    <run-dependency>
48
                        <specification-version>9.3</specification-version>
49
                    </run-dependency>
50
                </dependency>
51
                <dependency>
52
                    <code-name-base>org.openide.util.lookup</code-name-base>
53
                    <build-prerequisite/>
54
                    <compile-dependency/>
55
                    <run-dependency>
56
                        <specification-version>8.26</specification-version>
57
                    </run-dependency>
58
                </dependency>
59
            </module-dependencies>
60
            <test-dependencies>
61
                <test-type>
62
                    <name>unit</name>
63
                    <test-dependency>
64
                        <code-name-base>org.netbeans.libs.freemarker</code-name-base>
65
                    </test-dependency>
66
                    <test-dependency>
67
                        <code-name-base>org.netbeans.modules.editor.mimelookup</code-name-base>
68
                        <compile-dependency/>
69
                        <test/>
70
                    </test-dependency>
71
                    <test-dependency>
72
                        <code-name-base>org.netbeans.modules.editor.mimelookup.impl</code-name-base>
73
                    </test-dependency>
74
                    <test-dependency>
75
                        <code-name-base>org.netbeans.modules.masterfs</code-name-base>
76
                    </test-dependency>
77
                    <test-dependency>
78
                        <code-name-base>org.openide.awt</code-name-base>
79
                    </test-dependency>
80
                    <test-dependency>
81
                        <code-name-base>org.openide.dialogs</code-name-base>
82
                        <compile-dependency/>
83
                    </test-dependency>
84
                    <test-dependency>
85
                        <code-name-base>org.openide.loaders</code-name-base>
86
                        <compile-dependency/>
87
                    </test-dependency>
88
                    <test-dependency>
89
                        <code-name-base>org.openide.nodes</code-name-base>
90
                        <compile-dependency/>
91
                    </test-dependency>
92
                    <test-dependency>
93
                        <code-name-base>org.openide.util.lookup</code-name-base>
94
                        <compile-dependency/>
95
                        <test/>
96
                    </test-dependency>
97
                    <test-dependency>
98
                        <code-name-base>org.openide.modules</code-name-base>
99
                    </test-dependency>
100
                    <test-dependency>
101
                        <code-name-base>org.netbeans.modules.masterfs</code-name-base>
102
                    </test-dependency>
103
                    <test-dependency>
104
                        <code-name-base>org.netbeans.modules.editor.document</code-name-base>
105
                        <compile-dependency/>
106
                        <recursive/>
107
                    </test-dependency>
108
                    <test-dependency>
109
                        <code-name-base>org.netbeans.modules.editor.indent</code-name-base>
110
                        <compile-dependency/>
111
                        <recursive/>
112
                    </test-dependency>
113
                    <test-dependency>
114
                        <code-name-base>org.openide.util.ui</code-name-base>
115
                        <compile-dependency/>
116
                    </test-dependency>
117
                    <test-dependency>
118
                        <code-name-base>org.netbeans.modules.editor.lib</code-name-base>
119
                        <compile-dependency/>
120
                    </test-dependency>
121
                </test-type>
122
            </test-dependencies>
123
            <public-packages>
124
                <package>org.netbeans.api.templates</package>
125
                <package>org.openide.loaders</package>
126
            </public-packages>
127
        </data>
128
    </configuration>
129
</project>
(-)a/api.templates/src/org/netbeans/api/templates/CreateDescriptor.java (+158 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2014 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2014 Sun Microsystems, Inc.
41
 */
42
package org.netbeans.api.templates;
43
44
import java.util.Collections;
45
import java.util.Locale;
46
import java.util.Map;
47
import org.netbeans.api.annotations.common.CheckForNull;
48
import org.netbeans.api.annotations.common.NonNull;
49
import org.openide.filesystems.FileObject;
50
51
/**
52
 * Describes file creation request. The description is produced by the
53
 * {@link FileBuilder} and is sent out to
54
 * {@link CreateFromTemplateAttribute} and {@link CreateFromTemplateHandler} 
55
 * SPIs as the context for their work.
56
 * <p/>
57
 * The class is not thread-safe. Do not access the descriptor from a thread other
58
 * than executing the {@link CreateFromTemplateHandler} callbacks.
59
 * 
60
 * @author sdedic
61
 */
62
public final class CreateDescriptor {
63
    private final FileObject      template;
64
    private final FileObject      target;
65
    
66
    /**
67
     * The originally specified name for the new file
68
     */
69
    @SuppressWarnings("PackageVisibleField")
70
    String                name;
71
    
72
    /**
73
     * The proposed name - either specified, or computed
74
     */
75
    @SuppressWarnings("PackageVisibleField")
76
    String                proposedName;
77
    
78
    /**
79
     * Template parameters
80
     */
81
    @SuppressWarnings("PackageVisibleField")
82
    Map<String, Object>   parameters;
83
84
    /**
85
     * The locale used for file creation
86
     */
87
    Locale                locale = Locale.getDefault();
88
    
89
    /* package private */
90
    CreateDescriptor(FileObject template, FileObject target) {
91
        this.template = template;
92
        this.target = target;
93
    }
94
    
95
    /**
96
     * @return the template file
97
     */
98
    public @NonNull FileObject getTemplate() {
99
        return template;
100
    }
101
    
102
    /**
103
     * @return the target folder
104
     */
105
    public @NonNull FileObject getTarget() {
106
        return target;
107
    }
108
    
109
    /**
110
     * Provides the desired name for the created file. {@code null} can be
111
     * returned to indicate the filename should be derived automatically.
112
     * @return name for the created file
113
     */
114
    public @CheckForNull String getName() {
115
        return name;
116
    }
117
    
118
    /**
119
     * Provides a name proposed for the file. If the caller specified the name,
120
     * the value will be the same as {@link #getName}. A handler is encouraged
121
     * to use the proposed name if it does not require a certain naming scheme.
122
     * @return proposed name for the created file
123
     */
124
    public @NonNull String getProposedName() {
125
        return proposedName != null ? proposedName : name;
126
    }
127
    
128
    /**
129
     * Provides the desired user locale for creating the template
130
     * @return locale
131
     */
132
    public @NonNull Locale getLocale() {
133
        return locale;
134
    }
135
    
136
    /**
137
     * Provides value for the named key. Values are originally provided by
138
     * the caller, or the template itself; values can be provided also by
139
     * {@link CreateFromTemplateAttribute} implementors.
140
     * 
141
     * @param <T> value type.
142
     * @param n key name
143
     * @return named value or {@code null} if the key does not exist/has no value.
144
     */
145
    @CheckForNull
146
    public <T> T getValue(String n) {
147
        return (T)parameters.get(n);
148
    }
149
150
    /**
151
     * Provides access to the complete parameter map.
152
     * @return readonly string-value map.
153
     */
154
    public @NonNull Map<String, Object> getParameters() {
155
        return parameters == null ? Collections.<String, Object>emptyMap() : 
156
                Collections.unmodifiableMap(parameters);
157
    }
158
}
(-)a/api.templates/src/org/netbeans/api/templates/CreateFromTemplateAttributes.java (+67 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * Contributor(s):
28
 *
29
 * The Original Software is NetBeans. The Initial Developer of the Original
30
 * Software is Sun Microsystems, Inc.
31
 *
32
 * Portions Copyrighted 2007 Sun Microsystems, Inc.
33
 */
34
35
package org.netbeans.api.templates;
36
37
import java.util.Map;
38
39
/** This is an interface for <q>smart templating</q>.
40
 * Implementations of this class can be registered in the global {@link org.openide.util.Lookup}
41
 * and allows anyone provide additional parameters to each {@link CreateFromTemplateHandler}s
42
 * when a template is instantiating.
43
 * <p/>
44
 * Implementations are called in the order of appearance in Lookup. The positions less than 0 are
45
 * reserved for the platform. Implementations called later can see and override
46
 * values defined by earlier CreateFromTemplateAttributes.
47
 * <p/>
48
 * Read more in the <a href="@TOP@/architecture-summary.html#script">howto document</a>.
49
 * <p/>
50
 * This interface supersedes {@code CreateFromTemplateAttributesProvider} in {@code openide.loaders} module.
51
 * 
52
 * @author Svata Dedic
53
 */
54
public interface CreateFromTemplateAttributes {
55
    /** Called when a template is about to be instantiated to provide additional
56
     * values to the {@link CreateFromTemplateHandler} that will handle the 
57
     * template instantiation.
58
     * <p/>
59
     * If the returned Map defines the same value as some {@link CreateFromTemplateAttributes} registered
60
     * earlier, the Map's value takes precedence. Parameters supplied by the {@link FileBuilder} cannot be
61
     * overriden.
62
     * 
63
     * @param desc the creation request
64
     * @return map of named objects, or null
65
     */
66
    Map<String,?> attributesFor(CreateDescriptor desc);
67
}
(-)a/api.templates/src/org/netbeans/api/templates/CreateFromTemplateHandler.java (+86 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * Contributor(s):
28
 *
29
 * The Original Software is NetBeans. The Initial Developer of the Original
30
 * Software is Sun Microsystems, Inc.
31
 *
32
 * Portions Copyrighted 2007 Sun Microsystems, Inc.
33
 */
34
35
package org.netbeans.api.templates;
36
37
import java.io.IOException;
38
import java.util.List;
39
import org.netbeans.api.annotations.common.NonNull;
40
import org.openide.filesystems.FileObject;
41
42
/** This is an interface for <i>smart templating</i> that allows
43
 * any module to intercept calls to {@link DataObject#createFromTemplate} 
44
 * and handle them themselves. The NetBeans IDE provides default
45
 * implementation that allows use of Freemarker templating engine.
46
 * Read more in the <a href="@TOP@/architecture-summary.html#script">howto document</a>.
47
 *
48
 * @author Jaroslav Tulach
49
 * @author Svatopluk Dedic
50
 */
51
public abstract class CreateFromTemplateHandler {
52
    /** Method that allows a handler to reject a file. If all handlers
53
     * reject a file, regular processing defined in {@link DataObject#handleCreateFromTemplate}
54
     * is going to take place.
55
     * 
56
     * @param desc
57
     * @return true if this handler wants to handle the createFromTemplate operation
58
     */
59
    protected abstract boolean accept(CreateDescriptor desc);
60
    
61
    /** Handles the creation of new files. The Handler may create one or more files. The 
62
     * files should be ordered so that the "important" file (i.e. the one which is then presented
63
     * to the user etc) is ordered first in the list.
64
     * 
65
     * @param desc command objects that describes the file creation request
66
     * @return the newly create file
67
     * @throws IOException if something goes wrong with I/O
68
     */
69
    protected abstract @NonNull List<FileObject> createFromTemplate(
70
            CreateDescriptor    desc
71
    ) throws IOException;
72
73
    /**
74
     * Parameter to enable free file extension mode.
75
     * By default, the extension of the newly created file will be inherited
76
     * from the template. But if {@link #createFromTemplate} is called with this
77
     * parameter set to {@link Boolean#TRUE}
78
     * (such as from {@link DataObject#createFromTemplate(DataFolder,String,Map)}),
79
     * and the file name already seems to
80
     * include an extension (<samp>*.*</samp>), the handler should not append
81
     * any extension from the template.
82
     * @since org.openide.loaders 7.16
83
     * @see <a href="@org-netbeans-modules-projectuiapi@/org/netbeans/spi/project/ui/templates/support/Templates.SimpleTargetChooserBuilder.html#freeFileExtension()"><code>Templates.SimpleTargetChooserBuilder.freeFileExtension</code></a>
84
     */
85
    public static final String FREE_FILE_EXTENSION = "freeFileExtension"; // NOI18N
86
}
(-)a/api.templates/src/org/netbeans/api/templates/CreateFromTemplateImpl.java (+314 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2014 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2014 Sun Microsystems, Inc.
41
 */
42
package org.netbeans.api.templates;
43
44
import java.io.BufferedReader;
45
import java.io.IOException;
46
import java.io.InputStream;
47
import java.io.InputStreamReader;
48
import java.io.OutputStream;
49
import java.io.OutputStreamWriter;
50
import java.io.Reader;
51
import java.io.StringReader;
52
import java.io.StringWriter;
53
import java.io.Writer;
54
import java.nio.charset.Charset;
55
import java.text.Format;
56
import java.util.Collections;
57
import java.util.Date;
58
import java.util.HashMap;
59
import java.util.List;
60
import java.util.Map;
61
import javax.script.ScriptContext;
62
import javax.script.ScriptEngine;
63
import javax.script.ScriptException;
64
import org.netbeans.api.queries.FileEncodingQuery;
65
import org.netbeans.modules.templates.ScriptingCreateFromTemplateHandler;
66
import org.openide.filesystems.FileLock;
67
import org.openide.filesystems.FileObject;
68
import org.openide.filesystems.FileUtil;
69
import org.openide.util.Lookup;
70
import org.openide.util.MapFormat;
71
import org.openide.util.Parameters;
72
73
/**
74
 *
75
 * @author sdedic
76
 */
77
final class CreateFromTemplateImpl {
78
    private static final String PROP_TEMPLATE = "template"; // NOI18N
79
    private static final String EA_PREFORMATTED = "org-netbeans-modules-java-preformattedSource"; // NOI18N
80
    private static final String NEWLINE = "\n"; // NOI18N
81
    
82
    private final FileBuilder builder;
83
    private final CreateDescriptor desc;
84
    private Map<String, ?> originalParams;
85
    
86
    private CreateFromTemplateImpl(FileBuilder builder) {
87
        this.builder = builder;
88
        this.desc = builder.getDescriptor();
89
    }
90
    
91
    static List<FileObject> build(FileBuilder flb) throws IOException {
92
        CreateFromTemplateImpl impl = new CreateFromTemplateImpl(flb);
93
        return impl.build();
94
    }
95
    
96
    List<FileObject> build() throws IOException {
97
        // side effects: replaces the map in CreateDescriptor
98
        try {
99
            FileObject f = desc.getTemplate();
100
            FileObject folder = desc.getTarget();
101
            FileBuilder.Mode defaultMode = null;
102
            Format frm = null;
103
            Parameters.notNull("f", f);
104
            Parameters.notNull("folder", folder);
105
            assert defaultMode != FileBuilder.Mode.FORMAT || frm != null : "Format must be provided for Mode.FORMAT";
106
107
            if (!folder.isFolder()) {
108
                throw new IllegalArgumentException("Not a folder: "  + folder);
109
            }
110
            // also modifies desc.getParameters, result not needed.
111
            findTemplateParameters();
112
            computeEffectiveName();
113
114
            List<FileObject> pf = null;
115
            for (CreateFromTemplateHandler h : Lookup.getDefault().lookupAll(CreateFromTemplateHandler.class)) {
116
                if (h.accept(desc)) {
117
                    pf = h.createFromTemplate(desc);
118
                    assert pf != null && !pf.isEmpty();
119
                    break;
120
                }
121
            }
122
            if (pf != null) {
123
                return pf;
124
            }
125
            // side effects from findTemplateParameters still in effect...
126
            return Collections.singletonList(defaultCreate());
127
        } finally {
128
            // bring back the parameters
129
            builder.getDescriptor().parameters = (Map<String, Object>)originalParams;
130
        }
131
    }
132
    
133
    private void computeEffectiveName() {
134
        String name = desc.getName();
135
        if (name == null) {
136
            // name is not set - try to check parameters, if some template attribute handler
137
            // did not supply a suggestion:
138
            Object o = desc.getParameters().get("name");
139
            if (o instanceof String) {
140
                name = (String)o;
141
            } else {
142
                name = FileUtil.findFreeFileName(
143
                           desc.getTarget(), desc.getTemplate().getName (), desc.getTemplate().getExt ()
144
                       );
145
            }
146
        }
147
        desc.proposedName = name;
148
    }
149
    
150
    /**
151
     * Populates default values for template parameters. Each template can have its specific parameters and their default values
152
     * are defined by {@link CreateFromTemplateAttributes} SPI registered in the Lookup. The 'param' provides user-defined values,
153
     * which always take precedence over the defaults.
154
     * <p/>
155
     * Certain values are always filled in, if not specified:
156
     * <ul>
157
     * <li>{@code user} the invoking user name
158
     * <li>{@code date} system date : String
159
     * <li>{@code time} system time : String
160
     * <li>{@code dateTime} java.util.Date representation of the current system time
161
     * </ul>
162
     * 
163
     * @param template
164
     * @param folder
165
     * @param name
166
     * @param param
167
     * @return completed parameters
168
     */
169
    public Map<String,Object> findTemplateParameters() {
170
        // IMPORTANT: all map is exposed through CreateDescriptor !
171
        HashMap<String,Object> all = new HashMap<String,Object>();
172
        all.putAll(desc.getParameters());
173
        originalParams = desc.parameters;
174
        desc.parameters = all;
175
        for (CreateFromTemplateAttributes provider : Lookup.getDefault().lookupAll(CreateFromTemplateAttributes.class)) {
176
            Map<String,? extends Object> map = provider.attributesFor(desc);
177
            if (map != null) {
178
                for (Map.Entry<String,? extends Object> e : map.entrySet()) {
179
                    // allow each CFTA override previous CFTAs, but not user-provided params
180
                    if (originalParams == null || !originalParams.containsKey(e.getKey())) {
181
                        all.put(e.getKey(), e.getValue());
182
                    }
183
                }
184
            }
185
        }
186
        String name = desc.getName();
187
        if (!all.containsKey("name") && name != null) { // NOI18N
188
            String n = name;
189
            if (Boolean.TRUE.equals(all.get(CreateFromTemplateHandler.FREE_FILE_EXTENSION))) {
190
                n = name.replaceFirst("[.].*", "");
191
            }
192
            all.put("name", n); // NOI18N
193
            //desc.name = name;
194
        }
195
        Date d = new Date();
196
        if (!all.containsKey("dateTime")) { // NOI18N
197
            all.put("dateTime", d); // NOI18N
198
        }
199
        String ext = desc.getTemplate().getExt();
200
        if (!all.containsKey("nameAndExt") && name != null) { // NOI18N
201
            if (ext != null && ext.length() > 0 && originalParams != null &&
202
                    (!Boolean.TRUE.equals(originalParams.get(CreateFromTemplateHandler.FREE_FILE_EXTENSION)) || name.indexOf('.') == -1)) {
203
                all.put("nameAndExt", name + '.' + ext); // NOI18N
204
            } else {
205
                all.put("nameAndExt", name); // NOI18N
206
            }
207
        }
208
        return all;
209
    }
210
    
211
    /**
212
     * Creates the file using the default algorithm - no handler is willing to participate
213
     * @return created file
214
     * @throws IOException 
215
     */
216
    private FileObject defaultCreate() throws IOException {
217
//        if (pf != null || defaultMode == TemplateUtils.Mode.FAIL) {
218
//            return pf;
219
//        }
220
        Map<String, ?> params = desc.getParameters();
221
        FileBuilder.Mode defaultMode = builder.defaultMode;
222
        Format frm = builder.format;
223
        
224
        if (defaultMode != FileBuilder.Mode.COPY && frm instanceof MapFormat) {
225
            MapFormat mf = (MapFormat)frm;
226
            Map m = mf.getMap();
227
            for (String s: params.keySet()) {
228
                if (m.containsKey(s)) {
229
                    continue;
230
                }
231
                m.put(s, params.get(s));
232
            }
233
        }
234
        FileObject f = desc.getTemplate();
235
        String ext = desc.getTemplate().getExt();
236
        FileObject fo = desc.getTarget().createData (desc.getProposedName(), ext);
237
        boolean preformatted = false;
238
        Charset encoding = FileEncodingQuery.getEncoding(f);
239
        boolean success = false;
240
        FileLock lock = fo.lock ();
241
        try (InputStream is= f.getInputStream ();
242
            Reader reader = new InputStreamReader(is,encoding);
243
            BufferedReader r = new BufferedReader (reader)) {
244
245
            Object attr = f.getAttribute(EA_PREFORMATTED);
246
            if (attr != null && attr instanceof Boolean) {
247
                preformatted = ((Boolean)attr);
248
            }
249
            
250
            encoding = FileEncodingQuery.getEncoding(fo);
251
            
252
            //Document doc = ScriptingCreateFromTemplateHandler.createDocument(f.getMIMEType());
253
            ScriptEngine en = ScriptingCreateFromTemplateHandler.indentEngine();
254
            // PENDING: originally, preformatted meant that only changed
255
            // lines were formatted. Now preformatted is not formatted at all
256
            StringWriter sw = new StringWriter();
257
            try (
258
                OutputStream os=fo.getOutputStream(lock);
259
                OutputStreamWriter w = new OutputStreamWriter(os, encoding);
260
                Writer iw = preformatted || en == null ? w : sw) {
261
262
                String line = null;
263
                String current;
264
265
                while ((current = r.readLine ()) != null) {
266
                    if (line != null) {
267
                        // newline between lines
268
                        iw.append(NEWLINE);
269
                    }
270
                    if (frm != null) {
271
                        line = frm.format (current);
272
                    } else {
273
                        line = current;
274
                    }
275
                    iw.append(line);
276
                }
277
                iw.append(NEWLINE);
278
                iw.flush();
279
                
280
                if (en != null) {
281
                    en.getContext().setAttribute("mimeType", f.getMIMEType(), ScriptContext.ENGINE_SCOPE);
282
                    en.getContext().setWriter(w);
283
                    en.eval(new StringReader(sw.toString()));
284
                }
285
            }
286
            // copy attributes
287
            // hack to overcome package-private modifier in setTemplate(fo, boolean)
288
            FileUtil.copyAttributes(f, fo);
289
            fo.setAttribute(PROP_TEMPLATE, null);
290
            success = true;
291
        } catch (IOException ex) {
292
            try {
293
                fo.delete(lock);
294
            } catch (IOException ex2) {
295
            }
296
            throw ex;
297
        } catch (ScriptException ex) {
298
            IOException io = ex.getCause() instanceof IOException ? (IOException)ex.getCause() : null;
299
            try {
300
                fo.delete(lock);
301
            } catch (IOException ex2) {
302
            }
303
            throw io == null ? new IOException(ex) : io;
304
        } finally {
305
            if (!success) {
306
                // try to delete the malformed file:
307
                fo.delete(lock);
308
            }
309
            lock.releaseLock();
310
        }
311
        return fo;
312
    }
313
314
}
(-)a/api.templates/src/org/netbeans/api/templates/FileBuilder.java (+280 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2014 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2014 Sun Microsystems, Inc.
41
 */
42
package org.netbeans.api.templates;
43
44
import java.io.IOException;
45
import java.text.FieldPosition;
46
import java.text.Format;
47
import java.text.ParsePosition;
48
import java.util.Date;
49
import java.util.HashMap;
50
import java.util.List;
51
import java.util.Locale;
52
import java.util.Map;
53
import org.netbeans.api.annotations.common.CheckForNull;
54
import org.netbeans.api.annotations.common.NonNull;
55
import org.netbeans.api.annotations.common.NullAllowed;
56
import org.openide.filesystems.FileObject;
57
import org.openide.util.MapFormat;
58
59
/**
60
 * Fluent interface for file creation. The Builder is first parametrized. After
61
 * everything is set up, call {@link #build} to materialize the template using
62
 * the supplied parameters/settings.
63
 * <p/>
64
 * The create file(s) get names derived from the template and the existing target folder
65
 * contents (so that the filenames do not conflict with existing files). A desired
66
 * filename can be set up by {@link #name}.
67
 * <p/>
68
 * The file build request will be forwarded to {@link CreateFromTemplateHandler}s; if none
69
 * {@link CreateFromTemplateHandler#accept}s the request, the default procedure takes place,
70
 * depending on the {@link #defaultMode} setting (default: {@link Mode#COPY}).
71
 * <p/>
72
 * There are several values predefined:<ul>
73
 * <li>name - the created filename without extension
74
 * <li>nameAndExt - the created filename including the extension
75
 * <li>date - date of creation, printed in the default date format
76
 * <li>dateTime - {@link Date} object representing the creation time
77
 * <li>time - time of creation, printed in the default time format
78
 * <li>user - the user id of the user creating the file
79
 * </ul>
80
 * 
81
 * @author sdedic
82
 */
83
public final class FileBuilder {
84
    /**
85
     * Determines the default procedure for copying the template in {@link #createFromTemplate}.
86
     */
87
    public static enum Mode {
88
        /**
89
         * The template will be formatted using formatter.
90
         */
91
        FORMAT, 
92
        /**
93
         * The template will be just copied.
94
         */
95
        COPY, 
96
        /**
97
         * The template will not be processed if no custom {@link CreateFromTemplateHandler} handles it.
98
         */
99
        FAIL
100
    }
101
    
102
    /**
103
     * Creates a new FileBuilder for a specific template and target folder.
104
     * @param template the template to use.
105
     * @param target the target folder; must already exist.
106
     */
107
    public FileBuilder(@NonNull FileObject template, @NonNull FileObject target) {
108
        descriptor = new CreateDescriptor(template, target);
109
    }
110
    
111
    /**
112
     * Specifies the locale to be used during file creation.
113
     * The locale also applies to the standard parameters passed to the template (e.g. date and time representation).
114
     * @param l the locale
115
     * @return this FileBuilder instance.
116
     */
117
    public FileBuilder    useLocale(@NonNull Locale l) {
118
        descriptor.locale = l;
119
        return this;
120
    }
121
    
122
    /**
123
     * Sets the desired target file's name. 
124
     * 
125
     * @param n the name
126
     * @return this FileBuilder instance
127
     */
128
    public FileBuilder    name(String n) {
129
        descriptor.name = n;
130
        return this;
131
    }
132
    
133
    /**
134
     * Includes parameters for the template.
135
     * @param params the string-value pairs
136
     * @return this FileBuilder instance
137
     */
138
    public FileBuilder    withParameters(@NullAllowed Map<String, ?> params) {
139
        if (descriptor.parameters != null) {
140
            descriptor.parameters.putAll(params);
141
        } else {
142
            descriptor.parameters = params == null ? null : new HashMap<>(params);
143
        }
144
        return this;
145
    }
146
    
147
    /**
148
     * Adds a parameter to the template.
149
     * @param n parameter name
150
     * @param v the value
151
     * @return this FileBuilder instance
152
     */
153
    public FileBuilder    param(@NonNull String n, Object v) {
154
        if (descriptor.parameters == null) {
155
            descriptor.parameters = new HashMap<>();
156
        }
157
        descriptor.parameters.put(n, v);
158
        return this;
159
    }
160
    
161
    /**
162
     * Specifies the behaviour to be used when no {@link CreateFromTemplateHandler} accepts the template.
163
     * @param m the default processing mode
164
     * @return this FileBuilder instance
165
     * @see Mode for details
166
     */
167
    public FileBuilder    defaultMode(@NonNull Mode m) {
168
        this.defaultMode = m;
169
        return this;
170
    }
171
    
172
    /**
173
     * Uses the specified formatter for file creation. Also sets the default mode to
174
     * {@link Mode#FORMAT}. If the supplied Format instance <i>happens to be</i> a
175
     * {@link MapFormat}, the templating code will pass parameters produced by
176
     * {@link CreateFromTemplateAttributes} to the format when the target file
177
     * contents is generated.
178
     * 
179
     * @param def the format to use
180
     * @return  this FileBuilder instance
181
     * @see Mode for details on different modes
182
     */
183
    public FileBuilder    useFormat(@NonNull Format def) {
184
        this.format = def;
185
        return defaultMode(Mode.FORMAT);
186
    }
187
    
188
    /**
189
     * Creates the file(s) from template.
190
     * @return list of created files. If some file is 'master' or otherwise of high importance and represents
191
     * the file set, it should be placed first in the list.
192
     * @throws IOException if the creation fails
193
     */
194
    public @CheckForNull List<FileObject> build() throws IOException {
195
        return CreateFromTemplateImpl.build(this);
196
    }
197
    
198
    CreateDescriptor    getDescriptor() {
199
        return descriptor;
200
    }
201
    
202
    private final CreateDescriptor descriptor;
203
    
204
    @SuppressWarnings("PackageVisibleField")
205
    Mode    defaultMode;
206
    
207
    @SuppressWarnings("PackageVisibleField")
208
    Format  format;
209
    
210
211
    /**
212
     * Creates a new file based on the template. This convenience method is intended for easier
213
     * migration of clients using DataLoader templating API before {@link FileBuilder} introduction.
214
     * The method will collect parameters
215
     * tied to the template using registered {@link CreateFromTemplateAttributes} providers,
216
     * and will try to locate a willing {@link CreateFromTemplateHandler} that will create
217
     * the target file. If no such handler exists, and the {@code defaultCopy} parameter is true,
218
     * the file contents is just copied to the target location.
219
     * <p/>
220
     * If the {@code name} parameter is null, the function attempts to compute a suitable name
221
     * from the file.
222
     * <p/>
223
     * The default copy algorithm uses the supplied {@code format} to process tokens. A standard
224
     * format (using __TOKEN__) can be obtained by calling {@link #basicFormatter}.
225
     * <p/>
226
     * If the passed {@code name} is {@code null}, the implementation will pick a free name based on
227
     * the template's own name (see {@link FileUtil#findFreeFileName}).
228
     * @param f the template file
229
     * @param folder the target folder, must exist
230
     * @param name the desired name. If {@code null}, the implementation will choose the name.
231
     * @param attributes values to apply on the template. May be {@code null} = no values.
232
     * @return The created file, or {@code null} if no creation handler is located.
233
     * @throws IOException 
234
     */
235
    @SuppressWarnings("AssignmentToMethodParameter")
236
    @CheckForNull
237
    public static FileObject createFromTemplate(@NonNull FileObject f, @NonNull FileObject folder, 
238
            @NullAllowed String name, @NullAllowed Map<String, ?> attributes,
239
            Mode defaultMode) 
240
    throws IOException {
241
        Format frm = null;
242
        
243
        switch (defaultMode) {
244
            case FORMAT:
245
                MapFormat mf = new MapFormat(new HashMap());
246
                mf.setExactMatch(false);
247
                mf.setLeftBrace("__");
248
                mf.setRightBrace("__");
249
                frm = mf;
250
                break;
251
                
252
            case COPY:
253
                frm = new Format() {
254
                    @Override
255
                    public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
256
                        toAppendTo.append(obj);
257
                        return toAppendTo;
258
                    }
259
260
                    @Override
261
                    public Object parseObject(String source, ParsePosition pos) {
262
                        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
263
                    }
264
                };                    
265
                break;
266
        }
267
        FileBuilder fb = new FileBuilder(f, folder).
268
                            name(name).
269
                            withParameters(attributes).
270
                            useFormat(frm).
271
                            defaultMode(defaultMode);
272
        
273
        List<FileObject> fos = fb.build();
274
        if (fos == null || fos.isEmpty()) {
275
            return null;
276
        } else {
277
            return fos.iterator().next();
278
        }
279
    }
280
}
(-)a/api.templates/src/org/netbeans/api/templates/TemplateRegistration.java (+140 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common Development and
11
 * Distribution License("CDDL") (collectively, the "License"). You may not use
12
 * this file except in compliance with the License. You can obtain a copy of
13
 * the License at http://www.netbeans.org/cddl-gplv2.html or
14
 * nbbuild/licenses/CDDL-GPL-2-CP. See the License for the specific language
15
 * governing permissions and limitations under the License. When distributing
16
 * the software, include this License Header Notice in each file and include
17
 * the License file at nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
18
 * particular file as subject to the "Classpath" exception as provided by
19
 * Oracle in the GPL Version 2 section of the License file that accompanied
20
 * this code. If applicable, add the following below the License Header, with
21
 * the fields enclosed by brackets [] replaced by your own identifying
22
 * information: "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL or
25
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
26
 * elects to include this software in this distribution under the [CDDL or GPL
27
 * Version 2] license." If you do not indicate a single choice of license, a
28
 * recipient has the option to distribute your version of this file under
29
 * either the CDDL, the GPL Version 2 or to extend the choice of license to its
30
 * licensees as provided above. However, if you add GPL Version 2 code and
31
 * therefore, elected the GPL Version 2 license, then the option applies only
32
 * if the new code is made subject to such option by the copyright holder.
33
 *
34
 * Contributor(s):
35
 *
36
 * Portions Copyrighted 2011 Sun Microsystems, Inc.
37
 */
38
39
package org.netbeans.api.templates;
40
41
import java.lang.annotation.ElementType;
42
import java.lang.annotation.Retention;
43
import java.lang.annotation.RetentionPolicy;
44
import java.lang.annotation.Target;
45
import javax.script.ScriptEngineFactory;
46
47
/**
48
 * Registers a template the user can select.
49
 * May be placed on a class (with a default constructor) or static method (with no arguments)
50
 * to register an {@link InstantiatingIterator} for a custom template;
51
 * or on a package to register a plain-file template with no custom behavior.
52
 * @since 7.29
53
 * @see TemplateWizard
54
 * @see TemplateRegistrations
55
 * @see <a href="@org-netbeans-modules-projectuiapi@/org/netbeans/spi/project/ui/templates/support/package-summary.html"><code>org.netbeans.spi.project.ui.templates.support</code></a>
56
 */
57
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PACKAGE})
58
@Retention(RetentionPolicy.SOURCE)
59
public @interface TemplateRegistration {
60
    
61
    /**
62
     * Subfolder in which to place the template, such as {@code Other} or {@code Project/Standard}.
63
     */
64
    String folder();
65
    
66
    /**
67
     * Optional position within {@link #folder}.
68
     */
69
    int position() default Integer.MAX_VALUE;
70
71
    /**
72
     * Special file basename to use rather than inferring one from the declaring element,
73
     * when {@link #content} is empty.
74
     * Useful for pure templates referenced from {@code PrivilegedTemplates}.
75
     */
76
    String id() default "";
77
78
    /**
79
     * File contents, as resources relative to the package of this declaration.
80
     * A nonempty list is mandatory for a template registered on a package.
81
     * For a template with a custom iterator, the content may be omitted, though it may still be specified.
82
     * <p>Normally only a single file is specified, but for a multifile data object, list the primary entry first.
83
     * <p>The file basenames (incl. extension) of the actual template files (as in {@link TemplateWizard#getTemplate})
84
     * will be taken from the basename of the content resources, though a {@code .template} suffix
85
     * may be appended to prevent template resources in a source project from being misinterpreted.
86
     * For a "pure" custom iterator with no specified content, the template basename
87
     * defaults to the FQN of the class or method defining it but with {@code -} for {@code .} characters,
88
     * e.g. {@code pkg-Class-method}, but may be overridden with {@link #id}.
89
     * <p>Example usage for a simple, single-file template (with or without custom iterator):
90
     * <pre>content="resources/empty.php"</pre>
91
     * <p>For a form template:
92
     * <pre>content={"Login.java.template", "Login.form.template"}</pre>
93
     */
94
    String[] content() default {};
95
96
    /**
97
     * Localized label for the template.
98
     * Mandatory unless {@link #content} is specified, in which case it would be defaulted by the data node.
99
     * May use the usual {@code #key} syntax.
100
     */
101
    String displayName() default "";
102
103
    /**
104
     * Icon to use for the template.
105
     * Should be an absolute resource path (no initial slash).
106
     * Mandatory unless {@link #content} is specified, in which case it would be defaulted by the data node.
107
     */
108
    String iconBase() default "";
109
110
    /**
111
     * Optional but recommended relative resource path to an HTML description of the template.
112
     * @see TemplateWizard#getDescription
113
     */
114
    String description() default "";
115
116
    /**
117
     * Optional name of a script engine to use when processing file content, such as {@code freemarker}.
118
     * @see ScriptEngineFactory#getNames
119
     */
120
    String scriptEngine() default "";
121
122
    /**
123
     * Optional list of categories interpreted by the project system.
124
     */
125
    String[] category() default {};
126
127
    /**
128
     * Set to false if the template can be instantiated without a project.
129
     * @since 7.46
130
     */
131
    boolean requireProject() default true;
132
133
    /**
134
     * Default (pre-filled) target name for the template, without extension. May
135
     * use the usual {@code #key} syntax for localization or branding.
136
     *
137
     * @since 7.56
138
     */
139
    String targetName() default "";
140
}
(-)a/api.templates/src/org/netbeans/api/templates/TemplateRegistrations.java (+56 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common Development and
11
 * Distribution License("CDDL") (collectively, the "License"). You may not use
12
 * this file except in compliance with the License. You can obtain a copy of
13
 * the License at http://www.netbeans.org/cddl-gplv2.html or
14
 * nbbuild/licenses/CDDL-GPL-2-CP. See the License for the specific language
15
 * governing permissions and limitations under the License. When distributing
16
 * the software, include this License Header Notice in each file and include
17
 * the License file at nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
18
 * particular file as subject to the "Classpath" exception as provided by
19
 * Oracle in the GPL Version 2 section of the License file that accompanied
20
 * this code. If applicable, add the following below the License Header, with
21
 * the fields enclosed by brackets [] replaced by your own identifying
22
 * information: "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL or
25
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
26
 * elects to include this software in this distribution under the [CDDL or GPL
27
 * Version 2] license." If you do not indicate a single choice of license, a
28
 * recipient has the option to distribute your version of this file under
29
 * either the CDDL, the GPL Version 2 or to extend the choice of license to its
30
 * licensees as provided above. However, if you add GPL Version 2 code and
31
 * therefore, elected the GPL Version 2 license, then the option applies only
32
 * if the new code is made subject to such option by the copyright holder.
33
 *
34
 * Contributor(s):
35
 *
36
 * Portions Copyrighted 2011 Sun Microsystems, Inc.
37
 */
38
39
package org.netbeans.api.templates;
40
41
import java.lang.annotation.ElementType;
42
import java.lang.annotation.Retention;
43
import java.lang.annotation.RetentionPolicy;
44
import java.lang.annotation.Target;
45
46
/**
47
 * May be used to register multiple plain-file {@link TemplateRegistration}s.
48
 * Use on a package for simple templates, or on an iterator for multiple variants of a template
49
 * with different {@link TemplateRegistration#content}.
50
 * @since 7.29
51
 */
52
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PACKAGE})
53
@Retention(RetentionPolicy.SOURCE)
54
public @interface TemplateRegistrations {
55
    TemplateRegistration[] value();
56
}
(-)a/api.templates/src/org/netbeans/modules/templates/Bundle.properties (+7 lines)
Line 0 Link Here
1
OpenIDE-Module-Display-Category=Infrastructure
2
OpenIDE-Module-Long-Description=\
3
    Provides API to create files based on templates. Supports scripting in templates \
4
    and allows to plug in code that handles file creation, or supplies project or \
5
    environment data for template creation.
6
OpenIDE-Module-Name=File Templates
7
OpenIDE-Module-Short-Description=Supports file creation based on templates
(-)a/api.templates/src/org/netbeans/modules/templates/ScriptingCreateFromTemplateHandler.java (+186 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * Contributor(s):
28
 *
29
 * The Original Software is NetBeans. The Initial Developer of the Original
30
 * Software is Sun Microsystems, Inc.
31
 *
32
 * Portions Copyrighted 2007 Sun Microsystems, Inc.
33
 */
34
35
package org.netbeans.modules.templates;
36
37
import java.io.IOException;
38
import java.io.InputStreamReader;
39
import java.io.OutputStreamWriter;
40
import java.io.PrintWriter;
41
import java.io.Reader;
42
import java.io.StringReader;
43
import java.io.StringWriter;
44
import java.io.Writer;
45
import java.nio.charset.Charset;
46
import java.util.Collections;
47
import java.util.List;
48
import java.util.Map;
49
import javax.script.Bindings;
50
import javax.script.ScriptContext;
51
import javax.script.ScriptEngine;
52
import javax.script.ScriptEngineManager;
53
import javax.script.ScriptException;
54
import org.netbeans.api.queries.FileEncodingQuery;
55
import org.netbeans.api.templates.CreateDescriptor;
56
import org.netbeans.api.templates.CreateFromTemplateHandler;
57
import org.openide.filesystems.FileObject;
58
import org.openide.filesystems.FileUtil;
59
import org.openide.util.Lookup;
60
import org.openide.util.lookup.ServiceProvider;
61
62
63
/** Processes templates that have associated attribute
64
* with name of the scripting engine.
65
*
66
* @author  Jaroslav Tulach
67
*/
68
@ServiceProvider(service=CreateFromTemplateHandler.class)
69
public class ScriptingCreateFromTemplateHandler extends CreateFromTemplateHandler {
70
71
    public static final String SCRIPT_ENGINE_ATTR = "javax.script.ScriptEngine";
72
    
73
    private static ScriptEngineManager manager;
74
    
75
    private static final String ENCODING_PROPERTY_NAME = "encoding"; //NOI18N
76
    
77
    @Override
78
    public boolean accept(CreateDescriptor desc) {
79
        return engine(desc.getTemplate()) != null;
80
    }
81
82
    @Override
83
    public List<FileObject> createFromTemplate(CreateDescriptor desc) throws IOException {
84
        return Collections.singletonList(createFromTemplate(
85
            desc.getTemplate(),
86
            desc.getTarget(),
87
            desc.getName(),
88
            desc.getParameters()
89
        ));
90
    }
91
92
    private FileObject createFromTemplate(FileObject template, FileObject f,
93
                                            String name,
94
                                            Map<String, Object> values) throws IOException {
95
        boolean noExt = Boolean.TRUE.equals(values.get(FREE_FILE_EXTENSION)) && name.indexOf('.') != -1;
96
        
97
        String extWithDot;
98
        if (noExt) {
99
            extWithDot = null;
100
        } else {
101
            extWithDot = '.' + template.getExt();
102
            if (name.endsWith(extWithDot)) { // Test whether the extension happens to be there already
103
                // And remove it if yes, it will be appended to the unique name.
104
                name = name.substring(0, name.length() - extWithDot.length());
105
            }
106
        }
107
        
108
        String nameUniq = FileUtil.findFreeFileName(f, name, noExt ? null : template.getExt());
109
        FileObject output = FileUtil.createData(f, noExt ? nameUniq : nameUniq + extWithDot);
110
        Charset targetEnc = FileEncodingQuery.getEncoding(output);
111
        Charset sourceEnc = FileEncodingQuery.getEncoding(template);
112
        
113
        ScriptEngine eng = engine(template);
114
        Bindings bind = eng.getContext().getBindings(ScriptContext.ENGINE_SCOPE);
115
        bind.putAll(values);
116
        
117
        if(!values.containsKey(ENCODING_PROPERTY_NAME)) {
118
            bind.put(ENCODING_PROPERTY_NAME, targetEnc.name());
119
        }
120
        
121
        //Document doc = createDocument(template.getMIMEType());
122
        try (Writer w = new OutputStreamWriter(output.getOutputStream(), targetEnc);
123
             Reader is = new InputStreamReader(template.getInputStream(), sourceEnc);
124
            /*IndentWriter w2 = new IndentWriter(doc, 0, w, false) */) {
125
            StringWriter sw = new StringWriter();
126
            ScriptEngine eng2 = indentEngine();
127
            
128
            eng.getContext().setWriter(new PrintWriter(eng2 != null ? sw : w));
129
            //eng.getContext().setBindings(bind, ScriptContext.ENGINE_SCOPE);
130
            eng.getContext().setAttribute(FileObject.class.getName(), template, ScriptContext.ENGINE_SCOPE);
131
            eng.getContext().setAttribute(ScriptEngine.FILENAME, template.getNameExt(), ScriptContext.ENGINE_SCOPE);
132
            eng.eval(is);
133
            
134
            if (eng2 != null) {
135
                eng2.getContext().setAttribute("mimeType", template.getMIMEType(), ScriptContext.ENGINE_SCOPE);
136
                eng2.getContext().setWriter(w);
137
                eng2.eval(new StringReader(sw.toString()));
138
            }
139
        }catch (ScriptException ex) {
140
            IOException io = new IOException(ex.getMessage(), ex);
141
            throw io;
142
        }
143
        return output;
144
    }
145
    
146
    public static ScriptEngine indentEngine() {
147
        return getEngine(ID_INDENT_ENGINE);
148
    }
149
    
150
    private static final String ID_INDENT_ENGINE = "org.netbeans.api.templates.IndentEngine"; // NOI18N
151
    
152
    public static ScriptEngine getEngine(String engName) {
153
        synchronized (ScriptingCreateFromTemplateHandler.class) {
154
            if (manager == null) {
155
                ClassLoader loader = Lookup.getDefault().lookup(ClassLoader.class);
156
                manager = new ScriptEngineManager(loader != null ? loader : Thread.currentThread().getContextClassLoader());
157
            }
158
        }
159
        return manager.getEngineByName(engName);
160
    }
161
    
162
    private static ScriptEngine engine(FileObject fo) {
163
        Object obj = fo.getAttribute(SCRIPT_ENGINE_ATTR); // NOI18N
164
        if (obj instanceof ScriptEngine) {
165
            return (ScriptEngine)obj;
166
        }
167
        if (obj instanceof String) {
168
            return getEngine((String)obj);
169
        }
170
        return null;
171
    }
172
173
    /*
174
    public static Document createDocument(String mimeType) {
175
        Document doc;
176
        try {
177
            doc = LineDocumentUtils.createDocument(mimeType);
178
        } catch (IllegalArgumentException ex) {
179
            // mainly for tests
180
            doc = new PlainDocument();
181
            doc.putProperty("mimeType", mimeType);
182
        }
183
        return doc;
184
    }
185
    */
186
}
(-)a/api.templates/src/org/netbeans/modules/templates/TemplateProcessor2.java (+174 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common Development and
11
 * Distribution License("CDDL") (collectively, the "License"). You may not use
12
 * this file except in compliance with the License. You can obtain a copy of
13
 * the License at http://www.netbeans.org/cddl-gplv2.html or
14
 * nbbuild/licenses/CDDL-GPL-2-CP. See the License for the specific language
15
 * governing permissions and limitations under the License. When distributing
16
 * the software, include this License Header Notice in each file and include
17
 * the License file at nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
18
 * particular file as subject to the "Classpath" exception as provided by
19
 * Oracle in the GPL Version 2 section of the License file that accompanied
20
 * this code. If applicable, add the following below the License Header, with
21
 * the fields enclosed by brackets [] replaced by your own identifying
22
 * information: "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL or
25
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
26
 * elects to include this software in this distribution under the [CDDL or GPL
27
 * Version 2] license." If you do not indicate a single choice of license, a
28
 * recipient has the option to distribute your version of this file under
29
 * either the CDDL, the GPL Version 2 or to extend the choice of license to its
30
 * licensees as provided above. However, if you add GPL Version 2 code and
31
 * therefore, elected the GPL Version 2 license, then the option applies only
32
 * if the new code is made subject to such option by the copyright holder.
33
 *
34
 * Contributor(s):
35
 *
36
 * Portions Copyrighted 2011 Sun Microsystems, Inc.
37
 */
38
39
package org.netbeans.modules.templates;
40
41
import java.net.URI;
42
import java.net.URISyntaxException;
43
import java.util.Arrays;
44
import java.util.HashSet;
45
import java.util.Set;
46
import javax.annotation.processing.Processor;
47
import javax.annotation.processing.RoundEnvironment;
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.ElementKind;
52
import javax.lang.model.element.TypeElement;
53
import org.openide.filesystems.annotations.LayerGenerationException;
54
import org.netbeans.api.templates.TemplateRegistration;
55
import org.netbeans.api.templates.TemplateRegistrations;
56
import org.openide.filesystems.annotations.LayerBuilder;
57
import org.openide.filesystems.annotations.LayerGeneratingProcessor;
58
import org.openide.util.lookup.ServiceProvider;
59
60
/**
61
 * The implementation has moved from data systems. Part of the implementation is still there, 
62
 * as the {@code InstantiatingIterator} support requires 
63
 * @author sdedic
64
 */
65
@ServiceProvider(service=Processor.class)
66
@SupportedSourceVersion(SourceVersion.RELEASE_7)
67
public class TemplateProcessor2 extends LayerGeneratingProcessor {
68
69
    @Override public Set<String> getSupportedAnnotationTypes() {
70
        return new HashSet<String>(Arrays.asList(TemplateRegistration.class.getCanonicalName(), TemplateRegistrations.class.getCanonicalName()));
71
    }
72
73
    @Override protected boolean handleProcess(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) throws LayerGenerationException {
74
        if (roundEnv.processingOver()) {
75
            return false;
76
        }
77
        for (Element e : roundEnv.getElementsAnnotatedWith(TemplateRegistration.class)) {
78
            TemplateRegistration r = e.getAnnotation(TemplateRegistration.class);
79
            if (r == null) {
80
                continue;
81
            }
82
            process(e, r);
83
        }
84
        for (Element e : roundEnv.getElementsAnnotatedWith(TemplateRegistrations.class)) {
85
            TemplateRegistrations rr = e.getAnnotation(TemplateRegistrations.class);
86
            if (rr == null) {
87
                continue;
88
            }
89
            for (TemplateRegistration t : rr.value()) {
90
                process(e, t);
91
            }
92
        }
93
        return false;
94
    }
95
96
    private void process(Element e, TemplateRegistration t) throws LayerGenerationException {
97
        LayerBuilder builder = layer(e);
98
        String basename;
99
        if (!t.id().isEmpty()) {
100
            if (t.content().length > 0) {
101
                throw new LayerGenerationException("Cannot specify both id and content", e, processingEnv, t);
102
            }
103
            basename = t.id();
104
        } else if (t.content().length > 0) {
105
            basename = basename(t.content()[0]);
106
        } else {
107
            if (e.getKind() == ElementKind.CLASS) {
108
                basename = ((TypeElement) e).getQualifiedName().toString().replace('.', '-');
109
            } else if (e.getKind() == ElementKind.METHOD) {
110
                basename = ((TypeElement) e.getEnclosingElement()).getQualifiedName().toString().replace('.', '-') + '-' + e.getSimpleName();
111
            } else {
112
                throw new LayerGenerationException("cannot use @Template on a package without specifying content", e, processingEnv, t);
113
            }
114
        }
115
        String folder = "Templates/" + t.folder() + '/';
116
        LayerBuilder.File f = builder.file(folder + basename);
117
        f.boolvalue("template", true);
118
        f.position(t.position());
119
        if (!t.displayName().isEmpty()) {
120
            f.bundlevalue("displayName", t.displayName());
121
        }
122
        if (!t.iconBase().isEmpty()) {
123
            builder.validateResource(t.iconBase(), e, t, "iconBase", true);
124
            f.stringvalue("iconBase", t.iconBase());
125
        } else if (t.content().length == 0) {
126
            throw new LayerGenerationException("Must specify iconBase if content is not specified", e, processingEnv, t);
127
        }
128
        if (!t.description().isEmpty()) {
129
            f.urlvalue("instantiatingWizardURL", contentURI(e, t.description(), builder, t, "description"));
130
        }
131
//        if (e.getKind() != ElementKind.PACKAGE) {
132
//            f.instanceAttribute("instantiatingIterator", InstantiatingIterator.class);
133
//        }
134
        if (t.content().length > 0) {
135
            f.url(contentURI(e, t.content()[0], builder, t, "content").toString());
136
            for (int i = 1; i < t.content().length; i++) {
137
                builder.file(folder + basename(t.content()[i])).url(contentURI(e, t.content()[i], builder, t, "content").toString()).position(0).write();
138
            }
139
        }
140
        if (!t.scriptEngine().isEmpty()) {
141
            f.stringvalue(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, t.scriptEngine());
142
        }
143
        if (t.category().length > 0) {
144
            StringBuilder sb = new StringBuilder();
145
            for (String c : t.category()) {
146
                if (sb.length() > 0) {
147
                    sb.append(',');
148
                }
149
                sb.append(c);
150
            }
151
            f.stringvalue("templateCategory", sb.toString());
152
        }
153
        f.boolvalue("requireProject", t.requireProject());
154
        if (!t.targetName().trim().isEmpty()) {
155
            f.bundlevalue("targetName", t.targetName());                //NOI18N
156
        }
157
        f.write();
158
    }
159
160
    private static String basename(String relativeResource) {
161
        return relativeResource.replaceFirst(".+/", "").replaceFirst("[.]template$", "");
162
    }
163
164
    private URI contentURI(Element e, String relativePath, LayerBuilder builder, TemplateRegistration t, String annotationMethod) throws LayerGenerationException {
165
        String path = LayerBuilder.absolutizeResource(e, relativePath);
166
        builder.validateResource(path, e, t, annotationMethod, false);
167
        try {
168
            return new URI("nbresloc", "/" + path, null).normalize();
169
        } catch (URISyntaxException x) {
170
            throw new LayerGenerationException("could not translate " + path, e, processingEnv, t);
171
        }
172
    }
173
174
}
(-)a/api.templates/test/unit/data/golden/ClassWithoutReplacements.java (+7 lines)
Line 0 Link Here
1
/**
2
 *
3
 * @author sdedic
4
 */
5
public class Templateclass1 {
6
    
7
}
(-)a/api.templates/test/unit/data/golden/ForceNoReplacements.java (+7 lines)
Line 0 Link Here
1
/**
2
 *
3
 * @author __USER__
4
 */
5
public class Templateclass1 {
6
    
7
}
(-)a/api.templates/test/unit/data/golden/GeneratedMethodBody.java (+2 lines)
Line 0 Link Here
1
return 42;
2
(-)a/api.templates/test/unit/data/golden/GeneratedMethodBody2.java (+2 lines)
Line 0 Link Here
1
return 24;
2
(-)a/api.templates/test/unit/data/golden/SimpleReplacements.java (+7 lines)
Line 0 Link Here
1
/**
2
 *
3
 * @author foobar
4
 */
5
public class Templateclass1 {
6
    
7
}
(-)a/api.templates/test/unit/data/templates/ClassWithoutReplacements.java (+7 lines)
Line 0 Link Here
1
/**
2
 *
3
 * @author sdedic
4
 */
5
public class Templateclass1 {
6
    
7
}
(-)a/api.templates/test/unit/data/templates/GeneratedMethodBody.java (+14 lines)
Line 0 Link Here
1
<#--
2
A built-in Freemarker template (see http://freemarker.sourceforge.net) used for
3
filling the body of methods generated by the IDE. When editing the template,
4
the following predefined variables, that will be then expanded into
5
the corresponding values, could be used together with Java expressions and
6
comments:
7
${method_return_type}       a return type of a created method
8
${default_return_value}     a value returned by the method by default
9
${method_name}              name of the created method
10
${class_name}               qualified name of the enclosing class
11
${simple_class_name}        simple name of the enclosing class
12
-->
13
return ${default_return_value};
14
(-)a/api.templates/test/unit/data/templates/SimpleReplacements.java (+7 lines)
Line 0 Link Here
1
/**
2
 *
3
 * @author __USER__
4
 */
5
public class Templateclass1 {
6
    
7
}
(-)a/api.templates/test/unit/src/org/netbeans/api/templates/TemplateUtilsTest.java (+177 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2014 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2014 Sun Microsystems, Inc.
41
 */
42
package org.netbeans.api.templates;
43
44
import java.util.HashMap;
45
import java.util.Map;
46
import org.netbeans.junit.NbTestCase;
47
import org.netbeans.modules.templates.ScriptingCreateFromTemplateHandler;
48
import org.openide.filesystems.FileObject;
49
import org.openide.filesystems.FileUtil;
50
import org.openide.util.lookup.Lookups;
51
import org.openide.util.test.MockLookup;
52
53
/**
54
 *
55
 * @author sdedic
56
 */
57
public class TemplateUtilsTest extends NbTestCase {
58
59
    public TemplateUtilsTest(String name) {
60
        super(name);
61
    }
62
63
    @Override
64
    protected void setUp() throws Exception {
65
        super.setUp();
66
        clearWorkDir();
67
    }
68
    
69
    /**
70
     * Checks creation of templates without any special processing.
71
     * @throws Exception 
72
     */
73
    public void testCreatePlain() throws Exception {
74
        FileObject dataRoot = FileUtil.toFileObject(getDataDir());
75
        FileObject template = dataRoot.getFileObject("templates/ClassWithoutReplacements.java");
76
        template.setAttribute("template", Boolean.TRUE);
77
        FileObject workRoot = FileUtil.toFileObject(getWorkDir());
78
        FileObject result = FileBuilder.createFromTemplate(template, workRoot, "NoReplacements", null, FileBuilder.Mode.FORMAT);
79
        FileObject pass = dataRoot.getFileObject("golden/ClassWithoutReplacements.java");
80
        assertFile(FileUtil.toFile(result), FileUtil.toFile(pass));
81
    }
82
    
83
    /**
84
     * Forces plain default processing, although the template contains replaceable parts
85
     */
86
    public void testCreateForcePlain() throws Exception {
87
        FileObject dataRoot = FileUtil.toFileObject(getDataDir());
88
        FileObject template = dataRoot.getFileObject("templates/SimpleReplacements.java");
89
        template.setAttribute("template", Boolean.TRUE);
90
        FileObject workRoot = FileUtil.toFileObject(getWorkDir());
91
        Map m = new HashMap();
92
        m.put("USER", "foobar");
93
        FileObject result = FileBuilder.createFromTemplate(template, workRoot, "NoReplacements", m, FileBuilder.Mode.COPY);
94
        FileObject pass = dataRoot.getFileObject("golden/ForceNoReplacements.java");
95
        assertFile(FileUtil.toFile(result), FileUtil.toFile(pass));
96
    }
97
    
98
    /**
99
     * Uses a simple format, this is the mode applied by former implementation in MultiDataObject
100
     */
101
    public void testCreateReplaceSimple() throws Exception {
102
        clearWorkDir();
103
        FileObject dataRoot = FileUtil.toFileObject(getDataDir());
104
        FileObject template = dataRoot.getFileObject("templates/SimpleReplacements.java");
105
        template.setAttribute("template", Boolean.TRUE);
106
        FileObject workRoot = FileUtil.toFileObject(getWorkDir());
107
        Map m = new HashMap();
108
        m.put("USER", "foobar");
109
        FileObject result = FileBuilder.createFromTemplate(template, workRoot, "SimpleReplacements", m, FileBuilder.Mode.FORMAT);
110
        FileObject pass = dataRoot.getFileObject("golden/SimpleReplacements.java");
111
        assertFile(FileUtil.toFile(result), FileUtil.toFile(pass));
112
    }
113
    
114
    public void testScriptingTemplate() throws Exception {
115
        clearWorkDir();
116
        FileObject dataRoot = FileUtil.toFileObject(getDataDir());
117
        FileObject template = dataRoot.getFileObject("templates/GeneratedMethodBody.java");
118
        template.setAttribute("template", Boolean.TRUE);
119
        template.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "freemarker");
120
        FileObject workRoot = FileUtil.toFileObject(getWorkDir());
121
        Map m = new HashMap();
122
        m.put("default_return_value", "42");
123
        FileObject result = FileBuilder.createFromTemplate(template, workRoot, "GeneratedMethodBody", m, FileBuilder.Mode.FORMAT);
124
        FileObject pass = dataRoot.getFileObject("golden/GeneratedMethodBody.java");
125
        assertFile(FileUtil.toFile(result), FileUtil.toFile(pass));
126
    }
127
    
128
    @SuppressWarnings("PackageVisibleInnerClass")
129
    class DefaultValueAttribute implements CreateFromTemplateAttributes {
130
        @Override
131
        public Map<String, ?> attributesFor(CreateDescriptor desc) {
132
            FileObject template = desc.getTemplate();
133
            FileObject dataRoot = FileUtil.toFileObject(getDataDir());
134
            FileObject t = dataRoot.getFileObject("templates/GeneratedMethodBody.java");
135
            if (t != template) {
136
                return null;
137
            }
138
            
139
            Map m = new HashMap();
140
            m.put("default_return_value", "42");
141
            
142
            return m;
143
        }
144
    }
145
    
146
    public void testAddTemplateParameters() throws Exception {
147
        MockLookup.setLookup(
148
                Lookups.metaInfServices(getClass().getClassLoader()),
149
                Lookups.fixed(new DefaultValueAttribute()));
150
        clearWorkDir();
151
        FileObject dataRoot = FileUtil.toFileObject(getDataDir());
152
        FileObject template = dataRoot.getFileObject("templates/GeneratedMethodBody.java");
153
        template.setAttribute("template", Boolean.TRUE);
154
        template.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "freemarker");
155
        FileObject workRoot = FileUtil.toFileObject(getWorkDir());
156
        FileObject result = FileBuilder.createFromTemplate(template, workRoot, "GeneratedMethodBody", null, FileBuilder.Mode.FORMAT);
157
        FileObject pass = dataRoot.getFileObject("golden/GeneratedMethodBody.java");
158
        assertFile(FileUtil.toFile(result), FileUtil.toFile(pass));
159
    }
160
    
161
    public void testOverridenParameters() throws Exception {
162
        MockLookup.setLookup(
163
                Lookups.metaInfServices(getClass().getClassLoader()),
164
                Lookups.fixed(new DefaultValueAttribute()));
165
        clearWorkDir();
166
        FileObject dataRoot = FileUtil.toFileObject(getDataDir());
167
        FileObject template = dataRoot.getFileObject("templates/GeneratedMethodBody.java");
168
        template.setAttribute("template", Boolean.TRUE);
169
        template.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "freemarker");
170
        FileObject workRoot = FileUtil.toFileObject(getWorkDir());
171
        Map m = new HashMap();
172
        m.put("default_return_value", "24");
173
        FileObject result = FileBuilder.createFromTemplate(template, workRoot, "GeneratedMethodBody", m, FileBuilder.Mode.FORMAT);
174
        FileObject pass = dataRoot.getFileObject("golden/GeneratedMethodBody2.java");
175
        assertFile(FileUtil.toFile(result), FileUtil.toFile(pass));
176
    }
177
}
(-)a/api.templates/test/unit/src/org/netbeans/modules/templates/Bug138973Test.java (+267 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2008 Sun Microsystems, Inc.
41
 */
42
43
package org.netbeans.modules.templates;
44
45
import java.util.Enumeration;
46
import org.openide.loaders.*;
47
import java.io.BufferedReader;
48
import java.io.BufferedWriter;
49
import java.io.ByteArrayInputStream;
50
import java.io.IOException;
51
import java.io.InputStream;
52
import java.io.InputStreamReader;
53
import java.io.OutputStream;
54
import java.io.OutputStreamWriter;
55
import java.io.Reader;
56
import java.io.Writer;
57
import java.nio.ByteBuffer;
58
import java.nio.CharBuffer;
59
import java.nio.charset.Charset;
60
import java.nio.charset.CharsetDecoder;
61
import java.nio.charset.CharsetEncoder;
62
import java.nio.charset.CoderResult;
63
import java.util.Map;
64
import org.netbeans.api.editor.mimelookup.MimePath;
65
import org.netbeans.api.editor.mimelookup.test.MockMimeLookup;
66
import org.netbeans.api.queries.FileEncodingQuery;
67
import org.netbeans.junit.MockServices;
68
import org.netbeans.junit.NbTestCase;
69
import org.netbeans.modules.openide.loaders.DataObjectEncodingQueryImplementation;
70
import org.netbeans.modules.templates.ScriptingCreateFromTemplateHandler;
71
import org.netbeans.spi.queries.FileEncodingQueryImplementation;
72
import org.openide.filesystems.FileObject;
73
import org.openide.filesystems.FileUtil;
74
import org.openide.util.Enumerations;
75
import org.openide.util.Lookup;
76
import org.openide.util.lookup.Lookups;
77
78
/**
79
 *
80
 * @author  Marian Petras
81
 */
82
public class Bug138973Test extends NbTestCase {
83
84
    private static final String TESTING_TEXT = "print('This is a testing text.')";
85
    private static final TestCharset TEST_CHARSET = new TestCharset();
86
    private static final String EXT = ".test";
87
    private static final String TEMPLATE_NAME = "Bug138973TestTemplate";
88
    private static final String TEMPLATE_NAME_EXT = TEMPLATE_NAME + EXT;
89
    private static final String TESTFILE_NAME = "testfile";
90
    private static final String TESTFILE_NAME_EXT = TESTFILE_NAME + EXT;
91
92
    public Bug138973Test(String n) {
93
        super(n);
94
    }
95
96
    public void testBug() throws Exception {
97
        MockServices.setServices(Pool.class, DataObjectEncodingQueryImplementation.class);
98
        FileUtil.setMIMEType("test", "text/test");
99
        MockMimeLookup.setInstances(MimePath.get("text/test"), new TestEncoding());
100
//        FileUtil.createData(FileUtil.getConfigRoot(), "Editors/text/test/" + TestEncoding.class.getName().replace('.', '-') + ".instance");
101
102
        FileObject root = FileUtil.createMemoryFileSystem().getRoot();
103
        FileObject templatesFolder = root.createFolder("templates");
104
        assert templatesFolder != null;
105
        FileObject templateFile = FileUtil.createData(templatesFolder,
106
                                                      TEMPLATE_NAME_EXT);
107
        templateFile.setAttribute ("template", Boolean.TRUE);
108
        templateFile.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
109
        byte[] templateBytes = TESTING_TEXT.getBytes("ISO-8859-1");
110
        InputStream source = new ByteArrayInputStream(templateBytes);
111
        OutputStream target = templateFile.getOutputStream();
112
        FileUtil.copy(source, target);
113
        target.close();
114
        source.close();
115
        assert templateFile.getSize() != 0L;
116
        templateFile.setAttribute("template", Boolean.TRUE);
117
118
        assertEquals("text/test", templateFile.getMIMEType());
119
120
        assertEquals("No Decoder yet", 0, TestCharset.newDecoder);
121
        DataObject templateDataObj = DataObject.find(templateFile);
122
        DataObject newDataObj= templateDataObj.createFromTemplate(
123
                                                    DataFolder.findFolder(root),
124
                                                    TESTFILE_NAME);
125
126
        assertTrue("Decoder created", TestCharset.newDecoder >= 1);
127
    }
128
129
    public static final class SimpleTemplateHandler extends CreateFromTemplateHandler {
130
        @Override
131
        public boolean accept(FileObject orig) {
132
            return true;
133
        }
134
        @Override
135
        public FileObject createFromTemplate(FileObject template,
136
                                                FileObject targetFolder,
137
                                                String name,
138
                                                Map<String, Object> parameters) throws IOException {
139
            String nameUniq = FileUtil.findFreeFileName(targetFolder, name, template.getExt());
140
            FileObject newFile = FileUtil.createData(targetFolder, nameUniq + '.' + template.getExt());
141
142
            Charset templateEnc = FileEncodingQuery.getEncoding(template);
143
            Charset newFileEnc = FileEncodingQuery.getEncoding(newFile);
144
145
            InputStream is = template.getInputStream();
146
            Reader reader = new BufferedReader(new InputStreamReader(is, templateEnc));
147
            OutputStream os = newFile.getOutputStream();
148
            Writer writer = new BufferedWriter(new OutputStreamWriter(os, newFileEnc));
149
            int cInt;
150
            while ((cInt = reader.read()) != -1) {
151
                writer.write(cInt);
152
            }
153
            writer.close();
154
            reader.close();
155
156
            return newFile;
157
        }
158
    }
159
160
    public static final class SimpleLoader extends MultiFileLoader {
161
        public SimpleLoader() {
162
            super(SimpleObject.class.getName());
163
        }
164
        protected String displayName() {
165
            return "SimpleLoader";
166
        }
167
        @Override
168
        protected FileObject findPrimaryFile(FileObject fo) {
169
            if (fo.getNameExt().equals(TEMPLATE_NAME_EXT)) {
170
                return fo;
171
            }
172
            if (fo.getNameExt().equals(TESTFILE_NAME_EXT)) {
173
                return fo;
174
            }
175
            return null;
176
        }
177
        @Override
178
        protected MultiDataObject createMultiObject(FileObject primaryFile)
179
                                            throws DataObjectExistsException,
180
                                                   IOException {
181
            return new SimpleObject(this, primaryFile, isTestingFile(primaryFile));
182
        }
183
        @Override
184
        protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj,
185
                                                           FileObject primaryFile) {
186
            return new FE(obj, primaryFile);
187
        }
188
        @Override
189
        protected MultiDataObject.Entry createSecondaryEntry(MultiDataObject obj,
190
                                                             FileObject secondaryFile) {
191
            return new FE(obj, secondaryFile);
192
        }
193
        private static boolean isTestingFile(FileObject fileObj) {
194
            return fileObj.getNameExt().equals(TESTFILE_NAME_EXT);
195
        }
196
    }
197
198
    private static final class FE extends FileEntry {
199
        public FE(MultiDataObject mo, FileObject fo) {
200
            super(mo, fo);
201
        }
202
        @Override
203
        public FileObject createFromTemplate(FileObject f, String name) throws IOException {
204
            fail("FileEntry.createFromTemplate() should not be called");
205
            return null;
206
        }
207
    }
208
209
    public static final class SimpleObject extends MultiDataObject {
210
        private final Lookup lookup;
211
        public SimpleObject(SimpleLoader l,
212
                            FileObject fo,
213
                            boolean useSpecialEncoding)
214
                                              throws DataObjectExistsException {
215
            super(fo, l);
216
            lookup = useSpecialEncoding
217
                     ? Lookups.fixed(this, new TestEncoding())
218
                     : Lookups.singleton(this);
219
        }
220
        @Override
221
        public String getName() {
222
            return getPrimaryFile().getNameExt();
223
        }
224
        @Override
225
        public Lookup getLookup() {
226
            return lookup;
227
        }
228
    }
229
230
    public static final class TestEncoding extends FileEncodingQueryImplementation {
231
        @Override
232
        public Charset getEncoding(FileObject file) {
233
            return TEST_CHARSET;
234
        }
235
    }
236
237
    static final class TestCharset extends Charset {
238
        static int newDecoder;
239
        static int newEncoder;
240
241
        TestCharset() {
242
            super("test_charset", null);
243
        }
244
        @Override
245
        public boolean contains(Charset charset) {
246
            return true;
247
        }
248
        @Override
249
        public CharsetDecoder newDecoder() {
250
            newDecoder++;
251
            return Charset.forName("UTF-8").newDecoder();
252
        }
253
        @Override
254
        public CharsetEncoder newEncoder() {
255
            newEncoder++;
256
            return Charset.forName("UTF-8").newEncoder();
257
        }
258
    }
259
260
    public static final class Pool extends DataLoaderPool {
261
        @Override
262
        protected Enumeration<? extends DataLoader> loaders() {
263
            return Enumerations.singleton(SimpleLoader.getLoader(SimpleLoader.class));
264
        }
265
266
    }
267
}
(-)a/api.templates/test/unit/src/org/netbeans/modules/templates/CreateFromTemplateHandlerTest.java (+238 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * Contributor(s):
28
 *
29
 * The Original Software is NetBeans. The Initial Developer of the Original
30
 * Software is Sun Microsystems, Inc.
31
 *
32
 * Portions Copyrighted 2007 Sun Microsystems, Inc.
33
 */
34
35
package org.netbeans.modules.templates;
36
37
import java.io.IOException;
38
import java.util.ArrayList;
39
import java.util.Collections;
40
import java.util.Enumeration;
41
import java.util.List;
42
import java.util.Map;
43
import java.util.Set;
44
import org.netbeans.api.templates.CreateDescriptor;
45
import org.netbeans.api.templates.CreateFromTemplateAttributes;
46
import org.netbeans.junit.MockServices;
47
import org.netbeans.junit.NbTestCase;
48
import org.openide.filesystems.FileObject;
49
import org.openide.filesystems.FileUtil;
50
import org.openide.loaders.CreateFromTemplateHandler;
51
import org.openide.loaders.DataFolder;
52
import org.openide.loaders.DataLoader;
53
import org.openide.loaders.DataLoaderPool;
54
import org.openide.loaders.DataObject;
55
import org.openide.loaders.DataObjectExistsException;
56
import org.openide.loaders.FileEntry;
57
import org.openide.loaders.MultiDataObject;
58
import org.openide.loaders.MultiFileLoader;
59
import org.openide.util.Enumerations;
60
61
/**
62
 *
63
 * @author Jaroslav Tulach
64
 */
65
public class CreateFromTemplateHandlerTest extends NbTestCase {
66
    
67
    public CreateFromTemplateHandlerTest(String testName) {
68
        super(testName);
69
    }
70
    
71
    protected boolean runInEQ() {
72
        return true;
73
    }
74
    
75
    protected void setUp() throws Exception {
76
        Hand.acceptObject = new ArrayList<FileObject>();
77
        Hand.fileObject = new ArrayList<FileObject>();
78
        Hand.origObject = new ArrayList<FileObject>();
79
        Hand.name = null;
80
        Hand.parameters = null;
81
        
82
        MockServices.setServices(Hand.class, Attr.class, Pool.class);
83
    }
84
85
    protected void tearDown() throws Exception {
86
        super.tearDown();
87
    }
88
89
    public void testCreateFromTemplate() throws Exception {
90
        FileObject root = FileUtil.createMemoryFileSystem().getRoot();
91
        FileObject fo = FileUtil.createData(root, "simpleObject.txt");
92
        
93
        DataObject obj = DataObject.find(fo);
94
        
95
        DataFolder folder = DataFolder.findFolder(FileUtil.createFolder(root, "target"));
96
        
97
        Map<String,String> parameters = Collections.singletonMap("type", "empty");
98
        DataObject n = obj.createFromTemplate(folder, "complex", parameters);
99
        
100
        assertEquals("Created in right place", folder, n.getFolder());
101
        assertEquals("Created with right name", "complex.txt", n.getName());
102
        
103
        assertEquals("The right source", fo, Hand.origObject.get(0));
104
        assertEquals("The right source in query", fo, Hand.acceptObject.get(0));
105
        assertEquals("The right destiny folder", folder.getPrimaryFile(), Hand.fileObject.get(0));
106
        assertEquals("The right name", "complex", Hand.name);
107
        if (Hand.parameters.size() < 2) {
108
            fail("As least two: " + Hand.parameters + " but was " + Hand.parameters.size());
109
        }
110
        assertEquals("empty", Hand.parameters.get("type"));
111
        assertEquals("complex", Hand.parameters.get("name"));
112
        try {
113
            Hand.parameters.put("kuk", "buk");
114
        } catch (UnsupportedOperationException ex) {
115
            // ok
116
            return;
117
        }
118
        fail("Modifications shall be unsupported");
119
    }
120
    
121
    public static final class Hand extends CreateFromTemplateHandler {
122
        public static List<FileObject>  fileObject, origObject, acceptObject;
123
        public static String name;
124
        public static Map<String, Object> parameters;
125
    
126
        public boolean accept(FileObject fo) {
127
            acceptObject.add(fo);
128
            return true;
129
        }
130
131
        public FileObject createFromTemplate(
132
            FileObject orig, FileObject f, String n,
133
            Map<String, Object> p
134
        ) throws IOException {
135
            origObject.add(orig);
136
            fileObject.add(f);
137
            name = n;
138
            parameters = p;
139
140
            return FileUtil.copyFile(orig, f, name);
141
        }
142
    }
143
    
144
    public static final class Attr implements CreateFromTemplateAttributes {
145
        @Override
146
        public Map<String, ?> attributesFor(CreateDescriptor desc) {
147
            return Collections.singletonMap("name", desc.getProposedName());
148
        }
149
    }
150
    
151
    public static final class Pool extends DataLoaderPool {
152
        protected Enumeration<DataLoader> loaders() {
153
            return Enumerations.<DataLoader>array(new DataLoader[] { 
154
                SimpleLoader.getLoader(SimpleLoader.class),
155
                TwoPartLoader.getLoader(TwoPartLoader.class),
156
            });
157
        }
158
    }
159
    
160
    public static final class SimpleLoader extends MultiFileLoader {
161
        public SimpleLoader() {
162
            super(SimpleObject.class.getName());
163
        }
164
        protected String displayName() {
165
            return "SimpleLoader";
166
        }
167
        protected FileObject findPrimaryFile(FileObject fo) {
168
            if (fo.hasExt("prima")) {
169
                return fo;
170
            }
171
            return null;
172
        }
173
        protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException {
174
            return new SimpleObject(this, primaryFile);
175
        }
176
        protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj, FileObject primaryFile) {
177
            return new FE(obj, primaryFile);
178
        }
179
        protected MultiDataObject.Entry createSecondaryEntry(MultiDataObject obj, FileObject secondaryFile) {
180
            return new FileEntry(obj, secondaryFile);
181
        }
182
    }
183
    
184
    private static final class FE extends FileEntry {
185
        public FE(MultiDataObject mo, FileObject fo) {
186
            super(mo, fo);
187
        }
188
189
        @Override
190
        public FileObject createFromTemplate(FileObject f, String name) throws IOException {
191
            fail("I do not want to be called");
192
            return null;
193
        }
194
    }
195
    
196
    public static final class SimpleObject extends MultiDataObject {
197
        public SimpleObject(SimpleLoader l, FileObject fo) throws DataObjectExistsException {
198
            super(fo, l);
199
        }
200
        
201
        public String getName() {
202
            return getPrimaryFile().getNameExt();
203
        }
204
    }
205
    
206
    
207
208
    public static final class TwoPartLoader extends MultiFileLoader {
209
        public TwoPartLoader() {
210
            super(TwoPartObject.class.getName ());
211
        }
212
        protected String displayName() {
213
            return "TwoPart";
214
        }
215
        protected FileObject findPrimaryFile(FileObject fo) {
216
            if (fo.hasExt("java") || fo.hasExt("form")) {
217
                return org.openide.filesystems.FileUtil.findBrother(fo, "java");
218
            } else {
219
                return null;
220
            }
221
        }
222
        protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException {
223
            return new TwoPartObject(this, primaryFile);
224
        }
225
        protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj, FileObject primaryFile) {
226
            return new FE(obj, primaryFile);
227
        }
228
        protected MultiDataObject.Entry createSecondaryEntry(MultiDataObject obj, FileObject secondaryFile) {
229
            return new FE(obj, secondaryFile);
230
        }
231
    }
232
    public static final class TwoPartObject extends MultiDataObject {
233
        public TwoPartObject(TwoPartLoader l, FileObject folder) throws DataObjectExistsException {
234
            super(folder, l);
235
        }
236
    }
237
    
238
}
(-)a/api.templates/test/unit/src/org/netbeans/modules/templates/IndentEngineIntTest.java (+247 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * Contributor(s):
28
 *
29
 * The Original Software is NetBeans. The Initial Developer of the Original
30
 * Software is Sun Microsystems, Inc.
31
 *
32
 * Portions Copyrighted 2007 Sun Microsystems, Inc.
33
 */
34
35
package org.netbeans.modules.templates;
36
37
import java.awt.Dialog;
38
import java.io.IOException;
39
import java.io.OutputStream;
40
import java.util.Collections;
41
import java.util.Enumeration;
42
import java.util.Map;
43
import javax.swing.text.BadLocationException;
44
import org.netbeans.api.editor.mimelookup.MimePath;
45
import org.netbeans.api.editor.mimelookup.test.MockMimeLookup;
46
import org.netbeans.api.templates.FileBuilder;
47
import org.netbeans.junit.NbTestCase;
48
import org.netbeans.modules.editor.indent.spi.Context;
49
import org.netbeans.modules.editor.indent.spi.ExtraLock;
50
import org.netbeans.modules.editor.indent.spi.ReformatTask;
51
import org.openide.DialogDescriptor;
52
import org.openide.DialogDisplayer;
53
import org.openide.NotifyDescriptor;
54
import org.openide.filesystems.FileObject;
55
import org.openide.filesystems.FileUtil;
56
import org.openide.loaders.DataFolder;
57
import org.openide.loaders.DataLoader;
58
import org.openide.loaders.DataLoaderPool;
59
import org.openide.loaders.DataObject;
60
import org.openide.loaders.DataObjectExistsException;
61
import org.openide.loaders.FileEntry;
62
import org.openide.loaders.MultiDataObject;
63
import org.openide.loaders.MultiFileLoader;
64
import org.openide.util.Enumerations;
65
import org.openide.util.lookup.Lookups;
66
import org.openide.util.test.MockLookup;
67
68
/**
69
 *
70
 * @author Jaroslav Tulach
71
 */
72
public class IndentEngineIntTest extends NbTestCase {
73
    
74
    public IndentEngineIntTest(String testName) {
75
        super(testName);
76
    }
77
    
78
    protected boolean runInEQ() {
79
        return true;
80
    }
81
    
82
83
    @SuppressWarnings("deprecation")
84
    protected void setUp() throws Exception {
85
        MockLookup.setLookup(Lookups.fixed(new DD(), new Pool()), Lookups.metaInfServices(getClass().getClassLoader()));
86
        MockMimeLookup.setInstances(MimePath.get("text/jarda"), new IEImpl2());
87
        FileUtil.setMIMEType("txt", "text/jarda");
88
        clearWorkDir();
89
        super.setUp();
90
    }
91
92
    protected void tearDown() throws Exception {
93
        super.tearDown();
94
    }
95
    
96
    /**
97
     * Checks that the templating works without IndentEngine available
98
     * @throws Exception 
99
     */
100
    public void testWithoutEditorIndent() throws Exception {
101
        MockLookup.setLookup(Lookups.fixed(new DD(), new Pool()), 
102
                Lookups.exclude(Lookups.metaInfServices(getClass().getClassLoader()),
103
                        Class.forName("org.netbeans.modules.editor.indent.IndentScriptEngineHack$Factory")
104
                        ));
105
        FileObject dataRoot = FileUtil.toFileObject(getDataDir());
106
        FileObject template = dataRoot.getFileObject("templates/ClassWithoutReplacements.java");
107
        template.setAttribute("template", Boolean.TRUE);
108
        FileObject workRoot = FileUtil.toFileObject(getWorkDir());
109
        FileObject result = FileBuilder.createFromTemplate(template, workRoot, "NoReplacements", null, FileBuilder.Mode.FORMAT);
110
        FileObject pass = dataRoot.getFileObject("golden/ClassWithoutReplacements.java");
111
        assertFile(FileUtil.toFile(result), FileUtil.toFile(pass));
112
    }
113
114
    public void testCreateFromTemplateUsingFreemarker() throws Exception {
115
        FileObject root = FileUtil.createMemoryFileSystem().getRoot();
116
        FileObject fo = FileUtil.createData(root, "simpleObject.txt");
117
        OutputStream os = fo.getOutputStream();
118
        String txt = "print('<html><h1>'); print(title); print('</h1></html>');";
119
        os.write(txt.getBytes());
120
        os.close();
121
        fo.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "JavaScript");
122
        
123
        
124
        DataObject obj = DataObject.find(fo);
125
        
126
        DataFolder folder = DataFolder.findFolder(FileUtil.createFolder(root, "target"));
127
        
128
        Map<String,String> parameters = Collections.singletonMap("title", "Nazdar");
129
        DataObject n = obj.createFromTemplate(folder, "complex", parameters);
130
        
131
        assertEquals("Created in right place", folder, n.getFolder());
132
        assertEquals("Created with right name", "complex.txt", n.getName());
133
        
134
        String exp = ">lmth/<>1h/<radzaN>1h<>lmth<";
135
        assertEquals(exp, stripNewLines(readFile(n.getPrimaryFile())));
136
        
137
    }
138
    
139
    static String stripNewLines(String str) {
140
        return str.replace("\n", "").replace("\r", "");
141
    }
142
    
143
    private static String readFile(FileObject fo) throws IOException {
144
        return fo.asText();
145
    }
146
    
147
    public static final class DD extends DialogDisplayer {
148
        public Object notify(NotifyDescriptor descriptor) {
149
            throw new UnsupportedOperationException("Not supported yet.");
150
        }
151
152
        public Dialog createDialog(final DialogDescriptor descriptor) {
153
            throw new UnsupportedOperationException("Not supported yet.");
154
        }
155
    }
156
    
157
    public static final class Pool extends DataLoaderPool {
158
        protected Enumeration<DataLoader> loaders() {
159
            return Enumerations.<DataLoader>singleton(SimpleLoader.getLoader(SimpleLoader.class));
160
        }
161
    }
162
    
163
    public static final class SimpleLoader extends MultiFileLoader {
164
        public SimpleLoader() {
165
            super(SimpleObject.class.getName());
166
        }
167
        protected String displayName() {
168
            return "SimpleLoader";
169
        }
170
        protected FileObject findPrimaryFile(FileObject fo) {
171
            if (fo.hasExt("prima")) {
172
                return fo;
173
            }
174
            return null;
175
        }
176
        protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException {
177
            return new SimpleObject(this, primaryFile);
178
        }
179
        protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj, FileObject primaryFile) {
180
            return new FE(obj, primaryFile);
181
        }
182
        protected MultiDataObject.Entry createSecondaryEntry(MultiDataObject obj, FileObject secondaryFile) {
183
            return new FileEntry(obj, secondaryFile);
184
        }
185
    }
186
    
187
    private static final class FE extends FileEntry {
188
        public FE(MultiDataObject mo, FileObject fo) {
189
            super(mo, fo);
190
        }
191
192
        @Override
193
        public FileObject createFromTemplate(FileObject f, String name) throws IOException {
194
            fail("I do not want to be called");
195
            return null;
196
        }
197
198
        
199
        
200
    }
201
    
202
    public static final class SimpleObject extends MultiDataObject {
203
        public SimpleObject(SimpleLoader l, FileObject fo) throws DataObjectExistsException {
204
            super(fo, l);
205
        }
206
        
207
        public String getName() {
208
            return getPrimaryFile().getNameExt();
209
        }
210
    }
211
    
212
    public static final class IEImpl2 implements ReformatTask, ReformatTask.Factory {
213
        private Context context;
214
215
        public IEImpl2(Context context) {
216
            this.context = context;
217
        }
218
219
        public IEImpl2() {
220
        }
221
222
        @Override
223
        public void reformat() throws BadLocationException {
224
            int from = context.startOffset();
225
            int to = context.endOffset();
226
            int len = to - from;
227
            String s = context.document().getText(from, len);
228
            StringBuilder sb = new StringBuilder(s.length());
229
            for (int i = s.length() - 1; i >= 0; i--) {
230
                sb.append(s.charAt(i));
231
            }
232
            context.document().insertString(from, sb.toString(), null);
233
            context.document().remove(from + len, len);
234
        }
235
236
        @Override
237
        public ExtraLock reformatLock() {
238
            return null;
239
        }
240
241
        @Override
242
        public ReformatTask createTask(Context context) {
243
            return new IEImpl2(context);
244
        }
245
    }
246
247
}
(-)a/api.templates/test/unit/src/org/netbeans/modules/templates/SCFTHandlerTest.java (+507 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * Contributor(s):
28
 *
29
 * The Original Software is NetBeans. The Initial Developer of the Original
30
 * Software is Sun Microsystems, Inc.
31
 *
32
 * Portions Copyrighted 2007 Sun Microsystems, Inc.
33
 */
34
35
package org.netbeans.modules.templates;
36
37
import java.awt.Dialog;
38
import java.io.BufferedReader;
39
import java.io.IOException;
40
import java.io.InputStream;
41
import java.io.InputStreamReader;
42
import java.io.OutputStream;
43
import java.io.OutputStreamWriter;
44
import java.nio.CharBuffer;
45
import java.nio.charset.Charset;
46
import java.util.Collections;
47
import java.util.Enumeration;
48
import java.util.HashMap;
49
import java.util.Iterator;
50
import java.util.Map;
51
import java.util.logging.Level;
52
import java.util.logging.Logger;
53
import org.netbeans.junit.MockServices;
54
import org.netbeans.junit.NbTestCase;
55
import org.netbeans.spi.queries.FileEncodingQueryImplementation;
56
import org.openide.DialogDescriptor;
57
import org.openide.DialogDisplayer;
58
import org.openide.NotifyDescriptor;
59
import org.openide.filesystems.FileObject;
60
import org.openide.filesystems.FileStateInvalidException;
61
import org.openide.filesystems.FileSystem;
62
import org.openide.filesystems.FileUtil;
63
import org.openide.filesystems.LocalFileSystem;
64
import org.openide.loaders.DataFolder;
65
import org.openide.loaders.DataLoader;
66
import org.openide.loaders.DataLoaderPool;
67
import org.openide.loaders.DataObject;
68
import org.openide.loaders.DataObjectExistsException;
69
import org.openide.loaders.FileEntry;
70
import org.openide.loaders.MultiDataObject;
71
import org.openide.loaders.MultiFileLoader;
72
import org.openide.util.Enumerations;
73
74
/**
75
 *
76
 * @author Jaroslav Tulach
77
 */
78
public class SCFTHandlerTest extends NbTestCase {
79
    static {
80
        // confuse the system a bit, if your system runs with UTF-8 default locale...
81
        //System.setProperty("file.encoding", "cp1252");
82
    }
83
    
84
    public SCFTHandlerTest(String testName) {
85
        super(testName);
86
    }
87
    
88
    @Override
89
    protected boolean runInEQ() {
90
        return true;
91
    }
92
93
    @Override
94
    protected Level logLevel() {
95
        return Level.FINE;
96
    }
97
    
98
    @Override
99
    protected void setUp() throws Exception {
100
        clearWorkDir();
101
        MockServices.setServices(DD.class, Pool.class, FEQI.class);
102
    }
103
104
    @Override
105
    protected void tearDown() throws Exception {
106
        super.tearDown();
107
    }
108
109
    public void testCreateFromTemplateUsingFreemarker() throws Exception {
110
        FileObject root = FileUtil.createMemoryFileSystem().getRoot();
111
        FileObject fo = FileUtil.createData(root, "simpleObject.txt");
112
        OutputStream os = fo.getOutputStream();
113
        String txt = "print('<html><h1>'); print(title); print('</h1></html>');";
114
        os.write(txt.getBytes());
115
        os.close();
116
        fo.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
117
        
118
        
119
        DataObject obj = DataObject.find(fo);
120
        
121
        DataFolder folder = DataFolder.findFolder(FileUtil.createFolder(root, "target"));
122
        
123
        Map<String,String> parameters = Collections.singletonMap("title", "Nazdar");
124
        DataObject n = obj.createFromTemplate(folder, "complex", parameters);
125
        
126
        assertEquals("Created in right place", folder, n.getFolder());
127
        assertEquals("Created with right name", "complex.txt", n.getName());
128
        
129
        String exp = "<html><h1>Nazdar</h1></html>";
130
        assertEquals(exp, readFile(n.getPrimaryFile()));
131
        
132
    }
133
134
    public void testCreateWithNameAndExt() throws Exception {
135
        FileObject root = FileUtil.createMemoryFileSystem().getRoot();
136
        FileObject fo = FileUtil.createData(root, "simpleObject.txt");
137
        OutputStream os = fo.getOutputStream();
138
        String txt = "print('<html><h1>'); print(nameAndExt); print('</h1></html>')";
139
        os.write(txt.getBytes());
140
        os.close();
141
        fo.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
142
        
143
        
144
        DataObject obj = DataObject.find(fo);
145
        
146
        DataFolder folder = DataFolder.findFolder(FileUtil.createFolder(root, "target"));
147
        
148
        Map<String,String> parameters = Collections.emptyMap();
149
        DataObject n = obj.createFromTemplate(folder, "complex", parameters);
150
        
151
        assertEquals("Created in right place", folder, n.getFolder());
152
        assertEquals("Created with right name", "complex.txt", n.getName());
153
        
154
        String exp = "<html><h1>complex.txt</h1></html>";
155
        assertEquals(exp, readFile(n.getPrimaryFile()));
156
        
157
    }
158
159
    public void testCreateWithNameAndExtForForm() throws Exception {
160
        LocalFileSystem lfs = new LocalFileSystem();
161
        lfs.setRootDirectory(getWorkDir());
162
        FileObject root = lfs.getRoot();
163
        FileObject fo = FileUtil.createData(root, "j.java");
164
        OutputStream os = fo.getOutputStream();
165
        String txt = "print('<html><h1>'); print(nameAndExt); print('</h1></html>')";
166
        os.write(txt.getBytes());
167
        os.close();
168
        fo.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
169
        
170
        FileObject fo2 = FileUtil.createData(root, "j.form");
171
        OutputStream os2 = fo2.getOutputStream();
172
        String txt2 = "print('<html><h2>'); print(nameAndExt); print('</h2></html>')";
173
        os2.write(txt2.getBytes());
174
        os2.close();
175
        fo2.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
176
        
177
        DataObject obj = DataObject.find(fo);
178
        assertEquals("Both files", 2, obj.files().size());
179
        
180
        DataFolder folder = DataFolder.findFolder(FileUtil.createFolder(root, "target"));
181
        
182
        Map<String,String> parameters = Collections.emptyMap();
183
        DataObject n = obj.createFromTemplate(folder, "complex", parameters);
184
        
185
        assertEquals("Two files", 2, n.files().size());
186
        
187
        
188
        FileObject newForm = FileUtil.findBrother(n.getPrimaryFile(), "form");
189
        
190
        assertEquals("Primary file is java", "java", n.getPrimaryFile().getExt());
191
        
192
        assertNotNull("Form copied", newForm);
193
        DataObject frm = DataObject.find(newForm);
194
        assertSame("Form belongs to java", n, frm);
195
        
196
        assertEquals("Created in right place", folder, n.getFolder());
197
        assertEquals("Created with right name", "complex", n.getName());
198
        
199
        String exp = "<html><h1>complex.java</h1></html>";
200
        assertEquals("Primary file" + n.getPrimaryFile(), exp, readFile(n.getPrimaryFile()));
201
        
202
        String exp2 = "<html><h2>complex.form</h2></html>";
203
        assertEquals(exp2, readFile(newForm));
204
    }
205
    
206
    public void testBasePropertiesAlwaysPresent() throws Exception {
207
        FileObject root = FileUtil.createMemoryFileSystem().getRoot();
208
        FileObject fo = FileUtil.createData(root, "simpleObject.txt");
209
        OutputStream os = fo.getOutputStream();
210
        String txt = "print('<html><h1>'); print(name); print('</h1>');" +
211
            "print('<h2>'); print(date); print('</h2>');" +
212
            "print('<h3>'); print(time); print('</h3>');" +
213
            "print('<h4>'); print(user); print('</h4>');" +
214
            "print('<h4>'); print(dateTime.getTime()); print('</h4>');" +
215
            "print('</html>');";
216
        os.write(txt.getBytes());
217
        os.close();
218
        fo.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
219
        
220
        
221
        DataObject obj = DataObject.find(fo);
222
        
223
        DataFolder folder = DataFolder.findFolder(FileUtil.createFolder(root, "target"));
224
        
225
        Map<String,String> parameters = Collections.singletonMap("title", "Nazdar");
226
        DataObject n = obj.createFromTemplate(folder, "complex", parameters);
227
        
228
        assertEquals("Created in right place", folder, n.getFolder());
229
        assertEquals("Created with right name", "complex.txt", n.getName());
230
        
231
        String res = readFile(n.getPrimaryFile());
232
        
233
        if (res.indexOf("date") >= 0) fail(res);
234
        if (res.indexOf("time") >= 0) fail(res);
235
        if (res.indexOf("user") >= 0) fail(res);
236
        if (res.indexOf("name") >= 0) fail(res);
237
        if (res.indexOf("dateTime") >= 0) fail(res);
238
    }
239
    
240
    private static String readFile(FileObject fo) throws IOException {
241
        byte[] arr = new byte[(int)fo.getSize()];
242
        int len = fo.getInputStream().read(arr);
243
        assertEquals("Fully read", arr.length, len);
244
        return new String(arr);
245
    }
246
247
    private static String readChars(FileObject fo, Charset set) throws IOException {
248
        CharBuffer arr = CharBuffer.allocate((int)fo.getSize() * 2);
249
        BufferedReader r = new BufferedReader(new InputStreamReader(fo.getInputStream(), set));
250
        while (r.read(arr) != -1) {
251
            // again
252
        }
253
        r.close();
254
        
255
        arr.flip();
256
        return arr.toString();
257
    }
258
259
     public void testUTF8() throws Exception {
260
         FileObject root = FileUtil.getConfigRoot();
261
         FileObject xmldir = FileUtil.createFolder(root, "xml");
262
         FileObject xml = FileUtil.createData(xmldir, "class.txt");
263
         OutputStream os = xml.getOutputStream();
264
         FileUtil.copy(getClass().getResourceAsStream("utf8.xml"), os);
265
         xml.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
266
         os.close();
267
         
268
         DataObject obj = DataObject.find(xml);
269
         
270
         
271
         FileObject target = FileUtil.createFolder(FileUtil.createMemoryFileSystem().getRoot(), "dir");
272
         DataFolder folder = DataFolder.findFolder(FileUtil.createFolder(target, "target"));
273
         
274
         
275
         
276
         Charset set = Charset.forName("iso-8859-2");
277
         FEQI.fs = target.getFileSystem();
278
         FEQI.result = set;
279
         
280
         
281
         Map<String,String> parameters = Collections.singletonMap("title", "Nazdar");
282
         DataObject n = obj.createFromTemplate(folder, "complex", parameters);
283
         
284
         assertEquals("Created in right place", folder, n.getFolder());
285
         assertEquals("Created with right name", "complex.txt", n.getName());
286
         
287
         
288
         String read = readChars(n.getPrimaryFile(), set).replaceAll("println\\('", "").replaceAll("'\\);", "");
289
         String exp = readChars(xml, Charset.forName("utf-8")).replaceAll("println\\('", "").replaceAll("'\\);", "");
290
         assertEquals(exp, read);
291
         
292
     }
293
294
    public void testTemplateWizardCopiesItsPropertiesToMapForOverridenEntryOnMoreEntries() throws Exception {
295
        LocalFileSystem fs = new LocalFileSystem();
296
        fs.setRootDirectory(getWorkDir());
297
        
298
        FileObject root = fs.getRoot();
299
        FileObject fo = FileUtil.createData(root, "simpleObject.java");
300
        FileObject fo2 = FileUtil.createData(root, "simpleObject.form");
301
        fo.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
302
        fo2.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
303
304
        Charset set = Charset.forName("iso-8859-2");
305
        OutputStream os = fo2.getOutputStream();
306
        OutputStreamWriter w = new OutputStreamWriter(os, set);
307
        String txt = "print('skvělej tým, co nikdy neusíná - ěščřžýáíéúů')";
308
        w.write(txt);
309
        w.close();
310
        
311
        
312
        DataObject obj = DataObject.find(fo);
313
        assertEquals(TwoPartObject.class, obj.getClass());
314
        TwoPartObject tpo = (TwoPartObject)obj;
315
        tpo.encoding = set;
316
        
317
        FileObject root2 = FileUtil.createMemoryFileSystem().getRoot();
318
        DataFolder folder = DataFolder.findFolder(FileUtil.createFolder(root2, "target"));
319
        
320
        Map<String,String> parameters = Collections.singletonMap("type", "empty");
321
        
322
        FEQI.fs = root2.getFileSystem();
323
        FEQI.result = Charset.forName("UTF-8");
324
        
325
        DataObject n = obj.createFromTemplate(folder, "complex", parameters);
326
        Integer cnt = TwoPartLoader.queried.get(n.getPrimaryFile());
327
        assertEquals("No query", null, cnt);
328
        
329
        assertEquals("Created in right place", folder, n.getFolder());
330
        assertEquals("Created with right name", "complex", n.getName());
331
        Iterator<FileObject> it = n.files().iterator();
332
        it.next();
333
        FileObject snd = it.next();
334
        
335
        long length = snd.getSize();
336
        if (length <= 0) {
337
            fail("Too small file: " + length + " for " + snd);
338
        }
339
        InputStream is = snd.getInputStream();
340
        InputStreamReader r = new InputStreamReader(is, "UTF-8");
341
        char[] cbuf = new char[1024];
342
        int len = r.read(cbuf);
343
        if (len == -1) {
344
            fail("no input stream for " + snd);
345
        }
346
        String read = new String(cbuf, 0, len);
347
        txt = txt.replaceAll("print\\('", "").replaceAll("'\\)", "");
348
        
349
        assertEquals(txt, read);
350
    }
351
     
352
    public static final class DD extends DialogDisplayer {
353
        public Object notify(NotifyDescriptor descriptor) {
354
            throw new UnsupportedOperationException("Not supported yet.");
355
        }
356
357
        public Dialog createDialog(final DialogDescriptor descriptor) {
358
            throw new UnsupportedOperationException("Not supported yet.");
359
            /*
360
            return new JDialog() {
361
                @Deprecated
362
                public void show() {
363
                    for (Object object : descriptor.getOptions()) {
364
                        if (object instanceof JButton) {
365
                            JButton b = (JButton)object;
366
                            if (b.getText().equals("Finish")) {
367
                                descriptor.setValue(WizardDescriptor.FINISH_OPTION);
368
                                b.doClick();
369
                                return;
370
                            }
371
                        }
372
                    }
373
                    fail("Cannot find Finish button: " + Arrays.asList(descriptor.getOptions()));
374
                }
375
            };
376
             */
377
        }
378
    }
379
380
    public static final class FEQI extends FileEncodingQueryImplementation {
381
        public static FileSystem fs;
382
        public static Charset result;
383
    
384
        public Charset getEncoding(FileObject f) {
385
            try {
386
                if (f.getFileSystem() == fs) {
387
                    return result;
388
                }
389
                return null;
390
            } catch (FileStateInvalidException ex) {
391
                return null;
392
            }
393
        }
394
    }
395
    
396
    public static final class Pool extends DataLoaderPool {
397
        protected Enumeration<DataLoader> loaders() {
398
            return Enumerations.<DataLoader>array(new DataLoader[] { 
399
                TwoPartLoader.getLoader(TwoPartLoader.class),
400
                SimpleLoader.getLoader(SimpleLoader.class),
401
            });
402
        }
403
    }
404
    
405
    public static final class SimpleLoader extends MultiFileLoader {
406
        public SimpleLoader() {
407
            super(SimpleObject.class.getName());
408
        }
409
        protected String displayName() {
410
            return "SimpleLoader";
411
        }
412
        protected FileObject findPrimaryFile(FileObject fo) {
413
            if (fo.hasExt("prima")) {
414
                return fo;
415
            }
416
            return null;
417
        }
418
        protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException {
419
            return new SimpleObject(this, primaryFile);
420
        }
421
        protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj, FileObject primaryFile) {
422
            return new FE(obj, primaryFile);
423
        }
424
        protected MultiDataObject.Entry createSecondaryEntry(MultiDataObject obj, FileObject secondaryFile) {
425
            return new FileEntry(obj, secondaryFile);
426
        }
427
    }
428
    
429
    private static final class FE extends FileEntry {
430
        public FE(MultiDataObject mo, FileObject fo) {
431
            super(mo, fo);
432
        }
433
434
        @Override
435
        public FileObject createFromTemplate(FileObject f, String name) throws IOException {
436
            fail("I do not want to be called");
437
            return null;
438
        }
439
440
        
441
        
442
    }
443
    
444
    public static final class SimpleObject extends MultiDataObject {
445
        public SimpleObject(SimpleLoader l, FileObject fo) throws DataObjectExistsException {
446
            super(fo, l);
447
        }
448
        
449
        @Override
450
        public String getName() {
451
            return getPrimaryFile().getNameExt();
452
        }
453
    }
454
455
    static final Logger LOG = Logger.getLogger("tst.TwoPartLoader");
456
    public static final class TwoPartLoader extends MultiFileLoader {
457
        static Map<FileObject,Integer> queried = new HashMap<FileObject,Integer>();
458
        
459
        public TwoPartLoader() {
460
            super(TwoPartObject.class.getName ());
461
        }
462
        protected String displayName() {
463
            return "TwoPart";
464
        }
465
        protected FileObject findPrimaryFile(FileObject fo) {
466
            Integer i = queried.get(fo);
467
            queried.put(fo, i == null ? 1 : i + 1);
468
            FileObject ret;
469
            
470
            if (fo.hasExt("java") || fo.hasExt("form")) {
471
                ret = org.openide.filesystems.FileUtil.findBrother(fo, "java");
472
            } else {
473
                ret = null;
474
            }
475
            
476
            LOG.fine("findPrimaryFile for " + fo + " yeilded " + ret);
477
            return ret;
478
        }
479
        protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException {
480
            LOG.info("New data object for " + primaryFile);
481
            return new TwoPartObject(this, primaryFile);
482
        }
483
        protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj, FileObject primaryFile) {
484
            LOG.fine("new primary entry " + primaryFile);
485
            return new FE(obj, primaryFile);
486
        }
487
        protected MultiDataObject.Entry createSecondaryEntry(MultiDataObject obj, FileObject secondaryFile) {
488
            LOG.fine("new snd entry: " + secondaryFile);
489
            return new FE(obj, secondaryFile);
490
        }
491
    }
492
    public static final class TwoPartObject extends MultiDataObject {
493
        public TwoPartObject(TwoPartLoader l, FileObject folder) throws DataObjectExistsException {
494
            super(folder, l);
495
            getCookieSet().assign(FileEncodingQueryImplementation.class, eq);
496
        }
497
        private Charset encoding;
498
        private FileEncodingQueryImplementation eq = new FileEncodingQueryImplementation() {
499
500
            public Charset getEncoding(FileObject file) {
501
                return encoding;
502
            }
503
            
504
        };
505
    }
506
    
507
}
(-)a/api.templates/test/unit/src/org/netbeans/modules/templates/ScriptingCreateFromTemplateTest.java (+235 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * Contributor(s):
28
 *
29
 * The Original Software is NetBeans. The Initial Developer of the Original
30
 * Software is Sun Microsystems, Inc.
31
 *
32
 * Portions Copyrighted 2007 Sun Microsystems, Inc.
33
 */
34
35
package org.netbeans.modules.templates;
36
37
import java.io.IOException;
38
import java.io.OutputStream;
39
import java.nio.charset.Charset;
40
import java.util.Collections;
41
import java.util.HashMap;
42
import java.util.Map;
43
import javax.script.ScriptEngine;
44
import javax.swing.text.DefaultEditorKit;
45
import javax.swing.text.Document;
46
import org.netbeans.api.editor.mimelookup.MimePath;
47
import org.netbeans.api.queries.FileEncodingQuery;
48
import org.netbeans.junit.MockServices;
49
import org.netbeans.junit.NbTestCase;
50
import org.openide.filesystems.FileObject;
51
import org.openide.filesystems.FileUtil;
52
import org.openide.loaders.DataFolder;
53
import org.openide.loaders.DataObject;
54
import org.openide.loaders.DataObjectExistsException;
55
import org.openide.loaders.FileEntry;
56
import org.openide.loaders.MultiDataObject;
57
import org.openide.loaders.MultiFileLoader;
58
import org.netbeans.api.editor.mimelookup.test.MockMimeLookup;
59
import org.openide.loaders.CreateFromTemplateHandler;
60
import org.openide.util.SharedClassObject;
61
import org.openide.util.test.MockLookup;
62
63
/**
64
 *
65
 * @author Marek Fukala
66
 * @author Jaroslav Tulach
67
 */
68
public class ScriptingCreateFromTemplateTest extends NbTestCase {
69
    
70
    public ScriptingCreateFromTemplateTest(String testName) {
71
        super(testName);
72
    }
73
    
74
    @Override
75
    protected boolean runInEQ() {
76
        return true;
77
    }
78
    
79
    @Override
80
    protected void setUp() throws Exception {
81
        MockLookup.setInstances(SharedClassObject.findObject(SimpleLoader.class, true));
82
    }
83
84
    public void testCreateFromTemplateEncodingProperty() throws Exception {
85
        FileObject root = FileUtil.createMemoryFileSystem().getRoot();
86
        FileObject fo = FileUtil.createData(root, "simpleObject.txt");
87
        OutputStream os = fo.getOutputStream();
88
        os.write("print(encoding)".getBytes());
89
        os.close();
90
        assertEquals("content/unknown", fo.getMIMEType());
91
        fo.setAttribute ("template", Boolean.TRUE);
92
        assertEquals("content/unknown", fo.getMIMEType());
93
        fo.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
94
        
95
        DataObject obj = DataObject.find(fo);
96
        DataFolder folder = DataFolder.findFolder(FileUtil.createFolder(root, "target"));
97
        
98
        Map<String,String> parameters = Collections.emptyMap();
99
        DataObject inst = obj.createFromTemplate(folder, "complex", parameters);
100
        FileObject instFO = inst.getPrimaryFile();
101
        
102
        Charset targetEnc = FileEncodingQuery.getEncoding(instFO);
103
        assertNotNull("Template encoding is null", targetEnc);
104
        String instText = IndentEngineIntTest.stripNewLines(instFO.asText());
105
        assertEquals("Encoding in template doesn't match", targetEnc.name(), instText);
106
    }
107
108
    public void testFreeFileExtension() throws Exception {
109
        FileObject root = FileUtil.createMemoryFileSystem().getRoot();
110
        FileObject template = FileUtil.createData(root, "simple.pl");
111
        OutputStream os = template.getOutputStream();
112
        ScriptEngine jsEngine = new javax.script.ScriptEngineManager().getEngineByExtension("js");
113
        boolean isNashorn = (jsEngine != null && jsEngine.toString().indexOf("Nashorn") > 0);
114
        if (isNashorn) {
115
            // print() behaves like println() and println() does not exist:
116
            os.write("print('#!/usr/bin/perl'); print('# '+license); print('# '+name+' in '+nameAndExt);".getBytes());
117
        } else {
118
            os.write("println('#!/usr/bin/perl'); print('# ');println(license);print('# ');print(name);print(' in ');println(nameAndExt);".getBytes());
119
        }
120
        os.close();
121
        template.setAttribute("template", true);
122
        template.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
123
        Map<String,Object> parameters = new HashMap<String,Object>();
124
        parameters.put("license", "GPL");
125
        parameters.put(CreateFromTemplateHandler.FREE_FILE_EXTENSION, true);
126
        String newLine = isNashorn ? System.getProperty("line.separator") : "\n";
127
            FileObject inst = DataObject.find(template).createFromTemplate(DataFolder.findFolder(root), "nue", parameters).getPrimaryFile();
128
            assertEquals("#!/usr/bin/perl"+newLine+"# GPL"+newLine+"# nue in nue.pl"+newLine, inst.asText());
129
            assertEquals("nue.pl", inst.getPath());
130
            /* XXX perhaps irrelevant since typical wizards disable Finish in this condition
131
            inst = DataObject.find(template).createFromTemplate(DataFolder.findFolder(root), "nue", parameters).getPrimaryFile();
132
            assertEquals("#!/usr/bin/perl\n# GPL\n# nue_1 in nue_1.pl\n", inst.asText());
133
            assertEquals("nue_1.pl", inst.getPath());
134
             */
135
            inst = DataObject.find(template).createFromTemplate(DataFolder.findFolder(root), "nue.cgi", parameters).getPrimaryFile();
136
            assertEquals("#!/usr/bin/perl"+newLine+"# GPL"+newLine+"# nue in nue.cgi"+newLine, inst.asText());
137
            assertEquals("nue.cgi", inst.getPath());
138
            /* XXX
139
            inst = DataObject.find(template).createFromTemplate(DataFolder.findFolder(root), "nue.cgi", parameters).getPrimaryFile();
140
            assertEquals("#!/usr/bin/perl\n# GPL\n# nue_1 in nue_1.cgi\n", inst.asText());
141
            assertEquals("nue_1.cgi", inst.getPath());
142
             */
143
            inst = DataObject.find(template).createFromTemplate(DataFolder.findFolder(root), "explicit.pl", parameters).getPrimaryFile();
144
            assertEquals("#!/usr/bin/perl"+newLine+"# GPL"+newLine+"# explicit in explicit.pl"+newLine, inst.asText());
145
            assertEquals("explicit.pl", inst.getPath());
146
            /* XXX
147
            inst = DataObject.find(template).createFromTemplate(DataFolder.findFolder(root), "explicit.pl", parameters).getPrimaryFile();
148
            assertEquals("#!/usr/bin/perl\n# GPL\n# explicit_1 in explicit_1.pl\n", inst.asText());
149
            assertEquals("explicit_1.pl", inst.getPath());
150
             */
151
    }
152
    
153
    //fix for this test was rolled back because of issue #120865
154
    public void XtestCreateFromTemplateDocumentCreated() throws Exception {
155
        FileObject root = FileUtil.createMemoryFileSystem().getRoot();
156
        FileObject fo = FileUtil.createData(root, "simpleObject.txt");
157
        OutputStream os = fo.getOutputStream();
158
        os.write("test".getBytes());
159
        os.close();
160
        fo.setAttribute ("template", Boolean.TRUE);
161
        fo.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
162
163
        MockServices.setServices(MockMimeLookup.class);
164
        MockMimeLookup.setInstances(MimePath.parse("content/unknown"), new TestEditorKit());
165
        
166
        DataObject obj = DataObject.find(fo);
167
        DataFolder folder = DataFolder.findFolder(FileUtil.createFolder(root, "target"));
168
        
169
        assertFalse(TestEditorKit.createDefaultDocumentCalled);
170
        DataObject inst = obj.createFromTemplate(folder, "test");
171
        assertTrue(TestEditorKit.createDefaultDocumentCalled);
172
        
173
        String exp = "test";
174
        assertEquals(exp, inst.getPrimaryFile().asText());
175
    }
176
    
177
    public static final class SimpleLoader extends MultiFileLoader {
178
        public SimpleLoader() {
179
            super(SimpleObject.class.getName());
180
        }
181
        protected String displayName() {
182
            return "SimpleLoader";
183
        }
184
        protected FileObject findPrimaryFile(FileObject fo) {
185
            if (fo.hasExt("prima")) {
186
                return fo;
187
            }
188
            return null;
189
        }
190
        protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException {
191
            return new SimpleObject(this, primaryFile);
192
        }
193
        protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj, FileObject primaryFile) {
194
            return new FE(obj, primaryFile);
195
        }
196
        protected MultiDataObject.Entry createSecondaryEntry(MultiDataObject obj, FileObject secondaryFile) {
197
            return new FileEntry(obj, secondaryFile);
198
        }
199
    }
200
    
201
    private static final class FE extends FileEntry {
202
        public FE(MultiDataObject mo, FileObject fo) {
203
            super(mo, fo);
204
        }
205
206
        @Override
207
        public FileObject createFromTemplate(FileObject f, String name) throws IOException {
208
            fail("I do not want to be called");
209
            return null;
210
        }
211
    }
212
    
213
    public static final class SimpleObject extends MultiDataObject {
214
        public SimpleObject(SimpleLoader l, FileObject fo) throws DataObjectExistsException {
215
            super(fo, l);
216
        }
217
        
218
        public String getName() {
219
            return getPrimaryFile().getNameExt();
220
        }
221
    }
222
    
223
    private static final class TestEditorKit extends DefaultEditorKit {
224
        
225
        static boolean createDefaultDocumentCalled;
226
227
        @Override
228
        public Document createDefaultDocument() {
229
            createDefaultDocumentCalled = true;
230
            return super.createDefaultDocument();
231
        }
232
        
233
    }
234
235
}
(-)a/api.templates/test/unit/src/org/netbeans/modules/templates/utf8.xml (+4 lines)
Line 0 Link Here
1
println('<?xml version="1.0"?>');
2
println('<root>');
3
println('    Žluťoučký kůň skákal přes čtvero mezí.');
4
println('</root>');
(-)a/editor.indent/manifest.mf (-1 / +2 lines)
Lines 4-7 Link Here
4
OpenIDE-Module-Layer: org/netbeans/modules/editor/indent/resources/layer.xml
4
OpenIDE-Module-Layer: org/netbeans/modules/editor/indent/resources/layer.xml
5
AutoUpdate-Show-In-Client: false
5
AutoUpdate-Show-In-Client: false
6
OpenIDE-Module-Recommends: org.netbeans.modules.editor.indent.spi.CodeStylePreferences.Provider
6
OpenIDE-Module-Recommends: org.netbeans.modules.editor.indent.spi.CodeStylePreferences.Provider
7
OpenIDE-Module-Specification-Version: 1.40
7
OpenIDE-Module-Provides: org.netbeans.templates.IndentEngine
8
OpenIDE-Module-Specification-Version: 1.41
(-)a/editor.indent/nbproject/project.xml (-8 / +16 lines)
Lines 50-55 Link Here
50
            <code-name-base>org.netbeans.modules.editor.indent</code-name-base>
50
            <code-name-base>org.netbeans.modules.editor.indent</code-name-base>
51
            <module-dependencies>
51
            <module-dependencies>
52
                <dependency>
52
                <dependency>
53
                    <code-name-base>org.netbeans.modules.editor.document</code-name-base>
54
                    <build-prerequisite/>
55
                    <compile-dependency/>
56
                    <run-dependency>
57
                        <specification-version>1.3</specification-version>
58
                    </run-dependency>
59
                </dependency>
60
                <dependency>
53
                    <code-name-base>org.netbeans.modules.editor.mimelookup</code-name-base>
61
                    <code-name-base>org.netbeans.modules.editor.mimelookup</code-name-base>
54
                    <build-prerequisite/>
62
                    <build-prerequisite/>
55
                    <compile-dependency/>
63
                    <compile-dependency/>
Lines 94-107 Link Here
94
                    </run-dependency>
102
                    </run-dependency>
95
                </dependency>
103
                </dependency>
96
                <dependency>
104
                <dependency>
97
                    <code-name-base>org.openide.util.ui</code-name-base>
98
                    <build-prerequisite/>
99
                    <compile-dependency/>
100
                    <run-dependency>
101
                        <specification-version>9.3</specification-version>
102
                    </run-dependency>
103
                </dependency>
104
                <dependency>
105
                    <code-name-base>org.openide.util</code-name-base>
105
                    <code-name-base>org.openide.util</code-name-base>
106
                    <build-prerequisite/>
106
                    <build-prerequisite/>
107
                    <compile-dependency/>
107
                    <compile-dependency/>
Lines 117-122 Link Here
117
                        <specification-version>8.0</specification-version>
117
                        <specification-version>8.0</specification-version>
118
                    </run-dependency>
118
                    </run-dependency>
119
                </dependency>
119
                </dependency>
120
                <dependency>
121
                    <code-name-base>org.openide.util.ui</code-name-base>
122
                    <build-prerequisite/>
123
                    <compile-dependency/>
124
                    <run-dependency>
125
                        <specification-version>9.3</specification-version>
126
                    </run-dependency>
127
                </dependency>
120
            </module-dependencies>
128
            </module-dependencies>
121
            <test-dependencies>
129
            <test-dependencies>
122
                <test-type>
130
                <test-type>
(-)a/editor.indent/src/org/netbeans/modules/editor/indent/IndentScriptEngineHack.java (+225 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2014 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2014 Sun Microsystems, Inc.
41
 */
42
package org.netbeans.modules.editor.indent;
43
44
import java.io.IOException;
45
import java.io.Reader;
46
import java.util.Collections;
47
import java.util.List;
48
import javax.script.AbstractScriptEngine;
49
import javax.script.Bindings;
50
import javax.script.ScriptContext;
51
import javax.script.ScriptEngine;
52
import javax.script.ScriptEngineFactory;
53
import javax.script.ScriptException;
54
import javax.script.SimpleBindings;
55
import javax.swing.text.BadLocationException;
56
import javax.swing.text.Document;
57
import javax.swing.text.PlainDocument;
58
import javax.swing.text.Position;
59
import org.netbeans.api.editor.document.LineDocumentUtils;
60
import org.netbeans.modules.editor.indent.api.Reformat;
61
import org.openide.util.NbBundle;
62
import org.openide.util.lookup.ServiceProvider;
63
64
65
/**
66
 * The class implements a ScriptEngine, which is just a hacky way how to provide identation
67
 * to api.templates without introducing a new SPI.
68
 * 
69
 * @author sdedic
70
 */
71
public class IndentScriptEngineHack extends AbstractScriptEngine {
72
    private static final String ID_INDENT_ENGINE = "org.netbeans.api.templates.IndentEngine"; // NOI18N
73
74
    private IndentScriptEngineHack() {}
75
    
76
    @Override
77
    public Object eval(String text, ScriptContext context) throws ScriptException {
78
        Document doc;
79
        String mime = (String)context.getAttribute("mimeType"); // NOI18N
80
        try {
81
            doc = LineDocumentUtils.createDocument(mime);
82
        } catch (IllegalArgumentException ex) {
83
            // for testing: create a stupid document with a mimeType property
84
            doc = new PlainDocument();
85
            doc.putProperty("mimeType", mime); // NOI18N
86
        }
87
        Reformat reformat = Reformat.get(doc);
88
        reformat.lock();
89
        try {
90
            
91
            if (text.length() > 0) {
92
                try {
93
                    doc.insertString(0, text, null);
94
                    Position endPos = doc.createPosition(text.length());
95
                    reformat.reformat(0, endPos.getOffset());
96
                    int len = endPos.getOffset();
97
                    String reformattedText = doc.getText(0, len);
98
                    getContext().getWriter().write(reformattedText);
99
                } catch (BadLocationException e) {
100
                } catch (IOException ex) {
101
                    throw new ScriptException(ex);
102
                }
103
            }
104
        } finally {
105
            reformat.unlock();
106
        }
107
        return Boolean.TRUE;
108
    }
109
110
    @Override
111
    public Object eval(Reader reader, ScriptContext context) throws ScriptException {
112
        StringBuilder sb = new StringBuilder();
113
        char[] buf = new char[1024];
114
        int read;
115
        
116
        try {
117
            while ((read = reader.read(buf)) >= 0) {
118
                sb.append(buf, 0, read);
119
            }
120
        } catch (IOException ex) {
121
            throw new ScriptException(ex);
122
        }
123
        return eval(sb.toString());
124
    }
125
126
    @Override
127
    public Bindings createBindings() {
128
        return new SimpleBindings();
129
    }
130
131
    @Override
132
    public ScriptEngineFactory getFactory() {
133
        if (f == null) {
134
            f = new Factory();
135
        }
136
        return f;
137
    }
138
    
139
    private Factory f;
140
    
141
    @NbBundle.Messages({
142
        "NAME_IndentScriptEngine=NetBeans indentation"
143
    })
144
    @ServiceProvider(service = ScriptEngineFactory.class)
145
    public static class Factory implements ScriptEngineFactory {
146
147
        @Override
148
        public String getEngineName() {
149
            return Bundle.NAME_IndentScriptEngine();
150
        }
151
152
        @Override
153
        public String getEngineVersion() {
154
            return "1.0"; // NOI18N
155
        }
156
157
        @Override
158
        public List<String> getExtensions() {
159
            return Collections.emptyList();
160
        }
161
162
        @Override
163
        public List<String> getMimeTypes() {
164
            return Collections.emptyList();
165
        }
166
167
        @Override
168
        public List<String> getNames() {
169
            return Collections.singletonList(ID_INDENT_ENGINE);
170
        }
171
172
        @Override
173
        public String getLanguageName() {
174
            return ""; // NOI18N
175
        }
176
177
        @Override
178
        public String getLanguageVersion() {
179
            return "-1"; // NOI18N
180
        }
181
182
        @Override
183
        public Object getParameter(String key) {
184
            switch (key) {
185
                case ScriptEngine.ENGINE:
186
                    return getEngineName();
187
                case ScriptEngine.ENGINE_VERSION:
188
                    return getEngineVersion();
189
                case ScriptEngine.LANGUAGE:
190
                    return getLanguageName();
191
                case ScriptEngine.LANGUAGE_VERSION:
192
                    return getLanguageVersion();
193
                case ScriptEngine.NAME:
194
                    return getNames().get(0);
195
            }
196
            return null;
197
        }
198
199
        @Override
200
        public String getMethodCallSyntax(String obj, String m, String... args) {
201
            return null;
202
        }
203
204
        @Override
205
        public String getOutputStatement(String toDisplay) {
206
            return toDisplay;
207
        }
208
209
        @Override
210
        public String getProgram(String... statements) {
211
            StringBuilder sb = new StringBuilder();
212
            for (String s : statements) {
213
                sb.append(s);
214
            }
215
            return sb.toString();
216
        }
217
218
        @Override
219
        public ScriptEngine getScriptEngine() {
220
            return new IndentScriptEngineHack();
221
        }
222
        
223
    }
224
    
225
}
(-)a/java.source/nbproject/project.xml (+8 lines)
Lines 94-99 Link Here
94
                    </run-dependency>
94
                    </run-dependency>
95
                </dependency>
95
                </dependency>
96
                <dependency>
96
                <dependency>
97
                    <code-name-base>org.netbeans.api.templates</code-name-base>
98
                    <build-prerequisite/>
99
                    <compile-dependency/>
100
                    <run-dependency>
101
                        <specification-version>1.0</specification-version>
102
                    </run-dependency>
103
                </dependency>
104
                <dependency>
97
                    <code-name-base>org.netbeans.core.multiview</code-name-base>
105
                    <code-name-base>org.netbeans.core.multiview</code-name-base>
98
                    <build-prerequisite/>
106
                    <build-prerequisite/>
99
                    <compile-dependency/>
107
                    <compile-dependency/>
(-)a/java.source/src/org/netbeans/modules/java/IndentFileEntry.java (+1 lines)
Lines 115-120 Link Here
115
    /** Creates a new Java source from the template. Unlike the standard FileEntry.Format,
115
    /** Creates a new Java source from the template. Unlike the standard FileEntry.Format,
116
        this indents the resulting text using an indentation engine.
116
        this indents the resulting text using an indentation engine.
117
    */
117
    */
118
    @Override
118
    public FileObject createFromTemplate (FileObject f, String name) throws IOException {
119
    public FileObject createFromTemplate (FileObject f, String name) throws IOException {
119
        String ext = getFile ().getExt ();
120
        String ext = getFile ().getExt ();
120
121
(-)a/nbbuild/cluster.properties (+1 lines)
Lines 199-204 Link Here
199
        api.progress.compat8,\
199
        api.progress.compat8,\
200
        api.progress.nb,\
200
        api.progress.nb,\
201
        api.search,\
201
        api.search,\
202
        api.templates,\
202
        api.visual,\
203
        api.visual,\
203
        applemenu,\
204
        applemenu,\
204
        autoupdate.cli,\
205
        autoupdate.cli,\
(-)a/nbbuild/javadoctools/links.xml (+1 lines)
Lines 240-242 Link Here
240
<link href="${javadoc.docs.org-netbeans-modules-parsing-nb}" offline="true" packagelistloc="${netbeans.javadoc.dir}/org-netbeans-modules-parsing-nb"/>
240
<link href="${javadoc.docs.org-netbeans-modules-parsing-nb}" offline="true" packagelistloc="${netbeans.javadoc.dir}/org-netbeans-modules-parsing-nb"/>
241
<link href="${javadoc.docs.org-netbeans-modules-project-libraries-ui}" offline="true" packagelistloc="${netbeans.javadoc.dir}/org-netbeans-modules-project-libraries-ui"/>
241
<link href="${javadoc.docs.org-netbeans-modules-project-libraries-ui}" offline="true" packagelistloc="${netbeans.javadoc.dir}/org-netbeans-modules-project-libraries-ui"/>
242
<link href="${javadoc.docs.org-openide-filesystems-nb}" offline="true" packagelistloc="${netbeans.javadoc.dir}/org-openide-filesystems-nb"/>
242
<link href="${javadoc.docs.org-openide-filesystems-nb}" offline="true" packagelistloc="${netbeans.javadoc.dir}/org-openide-filesystems-nb"/>
243
<link href="${javadoc.docs.org-netbeans-api-templates}" offline="true" packagelistloc="${netbeans.javadoc.dir}/org-netbeans-api-templates"/>
(-)a/nbbuild/javadoctools/properties.xml (+1 lines)
Lines 239-241 Link Here
239
<property name="javadoc.docs.org-netbeans-modules-parsing-nb" value="${javadoc.web.root}/org-netbeans-modules-parsing-nb"/>
239
<property name="javadoc.docs.org-netbeans-modules-parsing-nb" value="${javadoc.web.root}/org-netbeans-modules-parsing-nb"/>
240
<property name="javadoc.docs.org-netbeans-modules-project-libraries-ui" value="${javadoc.web.root}/org-netbeans-modules-project-libraries-ui"/>
240
<property name="javadoc.docs.org-netbeans-modules-project-libraries-ui" value="${javadoc.web.root}/org-netbeans-modules-project-libraries-ui"/>
241
<property name="javadoc.docs.org-openide-filesystems-nb" value="${javadoc.web.root}/org-openide-filesystems-nb"/>
241
<property name="javadoc.docs.org-openide-filesystems-nb" value="${javadoc.web.root}/org-openide-filesystems-nb"/>
242
<property name="javadoc.docs.org-netbeans-api-templates" value="${javadoc.web.root}/org-netbeans-api-templates"/>
(-)a/nbbuild/javadoctools/replaces.xml (+1 lines)
Lines 239-241 Link Here
239
<replacefilter token="@org-netbeans-modules-parsing-nb@" value="${javadoc.docs.org-netbeans-modules-parsing-nb}"/>
239
<replacefilter token="@org-netbeans-modules-parsing-nb@" value="${javadoc.docs.org-netbeans-modules-parsing-nb}"/>
240
<replacefilter token="@org-netbeans-modules-project-libraries-ui@" value="${javadoc.docs.org-netbeans-modules-project-libraries-ui}"/>
240
<replacefilter token="@org-netbeans-modules-project-libraries-ui@" value="${javadoc.docs.org-netbeans-modules-project-libraries-ui}"/>
241
<replacefilter token="@org-openide-filesystems-nb@" value="${javadoc.docs.org-openide-filesystems-nb}"/>
241
<replacefilter token="@org-openide-filesystems-nb@" value="${javadoc.docs.org-openide-filesystems-nb}"/>
242
<replacefilter token="@org-netbeans-api-templates@" value="${javadoc.docs.org-netbeans-api-templates}"/>
(-)a/openide.loaders/apichanges.xml (+19 lines)
Lines 109-114 Link Here
109
<!-- ACTUAL CHANGES BEGIN HERE: -->
109
<!-- ACTUAL CHANGES BEGIN HERE: -->
110
110
111
  <changes>
111
  <changes>
112
      <change id="templates.separation">
113
          <api name="loaders"/>
114
          <summary>Separate template handling</summary>
115
          <version major="7" minor="59"/>
116
          <date day="14" month="10" year="2014"/>
117
          <author login="sdedic"/>
118
          <compatibility addition="no" deletion="no" binary="compatible" 
119
                         source="incompatible" deprecation="yes"/>
120
          <description>
121
              Template handling need not depend on Data System APIs, should be available
122
              for clients that only know FileSystems. Relevant interfaces moved to
123
              <code>openide.filesystems.templates</code> module; see javadoc for 
124
              <a href="@org-openide-filesystems-templates@/org/netbeans/api/templates/FileBuilder.html">
125
                  FileBuilder</a> for details.
126
          </description>
127
          <class package="org.openide.loaders" name="CreateFromTemplateAttributesProvider"/>
128
          <class package="org.openide.loaders" name="CreateFromTemplateHandler"/>
129
          <issue number=""/>
130
      </change>
112
      <change id="org.netbeans.api.templates.TemplateRegistration.targetName">
131
      <change id="org.netbeans.api.templates.TemplateRegistration.targetName">
113
          <api name="loaders"/>
132
          <api name="loaders"/>
114
          <summary>Introduce targetName for templates.</summary>
133
          <summary>Introduce targetName for templates.</summary>
(-)a/openide.loaders/arch.xml (-95 lines)
Lines 80-180 Link Here
80
    A lot of usecases is described <a href="@TOP@/org/openide/loaders/doc-files/api.html" >in the javadoc</a>. Here 
80
    A lot of usecases is described <a href="@TOP@/org/openide/loaders/doc-files/api.html" >in the javadoc</a>. Here 
81
    is the list of some faqs:
81
    is the list of some faqs:
82
  
82
  
83
    <usecase id="script" name="Using Scripting and Templating Languages" >
84
        <p>
85
        Often many people require ability to create a "clever" template - e.g.
86
        write piece of simple text and at the time of its 
87
        <a href="@TOP@/org/openide/loaders/DataObject.html#createFromTemplate(org.openide.loaders.DataFolder,%20java.lang.String,%20java.util.Map)">
88
            processing
89
        </a>
90
        do some advanced changes to it using either 
91
        <a name="script">scripting or templating</a> languages.
92
        </p>
93
        
94
        <p>
95
        This traditionally used to be a bit complicated task, however since 
96
        version 6.1 there are new interfaces 
97
        <api name="org.openide.loaders.CreateFromTemplateHandler" category="official" group="lookup" type="export"
98
        url="@TOP@/org/openide/loaders/CreateFromTemplateHandler.html">
99
            can be registered as a services in a lookup and it is reponsible
100
            for handling the whole copy of the template file(s) to the destination
101
            folder.
102
        </api> and 
103
        <api name="org.openide.loaders.CreateFromTemplateAttributesProvider" category="official" group="lookup" type="export"
104
        url="@TOP@/org/openide/loaders/CreateFromTemplateAttributesProvider.html">
105
            can be registered as a services in a lookup and it is reponsible
106
            for providing "hints" - e.g. map mapping strings to various objects.
107
        </api> and these interfaces allow anyone to extend the behaviour during
108
        creation of new files without writing new 
109
        <a href="@TOP@/org/openide/loaders/DataLoader.html">DataLoader</a> and co.
110
        </p>
111
        
112
        <p style="margin-left: 0.2in; margin-right: 0.2in; margin-top: 0.2in; margin-bottom: 0.2in; border: 1.00pt solid #9999cc; padding: 0.1in; color: #666699">
113
            <b>Smart Templating Quick How-To</b>
114
            <br/>
115
            
116
            First of all create a file in your module layer located somewhere
117
            under the <code>Templates/</code> folder. Make it a template by
118
            adding &lt;attr name="template" boolvalue="true"/&gt;. Associate
119
            this template with a scripting language, for example by
120
            &lt;attr name="javax.script.ScriptEngine" stringvalue="freemarker"/&gt;.
121
            Now make sure that the scripting language integration is also available
122
            by requesting a token in standard format, for freemarker just put
123
            <code>OpenIDE-Module-Needs: javax.script.ScriptEngine.freemarker</code>
124
            in your manifest. This tells the NetBeans module system that a 
125
            module providing integration with such scripting engine has to be 
126
            enabled. Now you can use regular script language tags inside of
127
            your template file. When you write your <code>instantiate</code>
128
            method in your wizard, you can create a Map&lt;String,Object&gt; and
129
            fill it with parameters collected from your wizard and then pass it 
130
            to
131
            <a href="@TOP@/org/openide/loaders/DataObject.html#createFromTemplate(org.openide.loaders.DataFolder,%20java.lang.String,%20java.util.Map)">                
132
                createFromTemplate(targetFolder, targetName, mapWithParameters)
133
            </a>. This will invoke the scripting language and make the 
134
            <code>mapWithParameters</code> values available to it. Beyond this 
135
            there is few standard parameters predefined including <code>name</code>, <code>user</code>, <code>date</code>, <code>time</code>, etc.
136
            and also additional parameters are collected from all registered
137
            <a href="@TOP@/org/openide/loaders/CreateFromTemplateAttributesProvider.html">CreateFromTemplateAttributesProvider</a>s.
138
        </p>
139
        
140
        <p>
141
        Moreover there is a built in support for scripting languages in
142
        the standard NetBeans IDE. If a template is annotated with
143
        <api name="javax.script.ScriptEngine" category="official" group="property" type="export">
144
            a property that can be associated to templates that either should
145
            return real instance of <code>ScriptEngine</code> interface or
146
            a <code>String</code> name of the engine that is then used to
147
            search for it in the <code>javax.script.ScriptEngineManager</code>.
148
            Usually the <a href="http://freemarker.sourceforge.net/">freemarker</a> engine is the one that is 
149
            supported by the NetBeans IDE - if your module wants to use it
150
            then include a token dependency <code>OpenIDE-Module-Needs: javax.script.ScriptEngine.freemarker</code>
151
            in your manifest file (also accessible through project customizer GUI)
152
            to indicate to the system that you need it.
153
        </api>
154
        then the scripting engine is then used to process the template and
155
        generate the output file. While running the engine one can rely
156
        on few predefined properties:
157
        </p>
158
159
        <ul>
160
            <li><api name="name" category="stable" group="property" type="export"> contains the name of the <a href="@TOP@/org/openide/loaders/DataObject.html">DataObject</a> that is being created</api></li>
161
            <li><api name="user" category="stable" group="property" type="export"> contains the name the user</api></li>
162
            <li><api name="nameAndExt" category="stable" group="property" type="export"> contains the name and extension of the file that is being created</api></li>
163
            <li><api name="date" category="stable" group="property" type="export"> contains <code>String</code> representing the current day like <code>23. 3. 2007</code></api></li>
164
            <li><api name="time" category="stable" group="property" type="export"> contains <code>String</code> the current time like <code>17:18:30</code></api></li>
165
            <li><api name="dateTime" category="stable" group="property" type="export"> contains <code>java.util.Date</code> representing current data and time like</api></li>
166
            <li><api name="encoding" category="stable" group="property" type="export"> contains <code>String</code> the file encoding of the template instance</api></li>
167
        </ul>
168
        
169
        <p>
170
        Other properties can indeed be provided by
171
        <a href="@TOP@/org/openide/loaders/CreateFromTemplateAttributesProvider.html">CreateFromTemplateAttributesProvider</a>s.
172
        After processing, the output is also sent to appropriate
173
        <code>org.openide.text.IndentEngine</code> associated
174
        with the mime type of the template, for formating.
175
        </p>
176
    </usecase>
177
      
178
    <usecase id="add-action-to-folder" name="How to add action to folder's popup menu?" >
83
    <usecase id="add-action-to-folder" name="How to add action to folder's popup menu?" >
179
    <api name="Loaders-folder-any-Actions" category="stable" group="layer" type="export" >
84
    <api name="Loaders-folder-any-Actions" category="stable" group="layer" type="export" >
180
    The actions that the default folder loader shows in its popup menu are read from
85
    The actions that the default folder loader shows in its popup menu are read from
(-)a/openide.loaders/manifest.mf (-1 / +1 lines)
Lines 1-6 Link Here
1
Manifest-Version: 1.0
1
Manifest-Version: 1.0
2
OpenIDE-Module: org.openide.loaders
2
OpenIDE-Module: org.openide.loaders
3
OpenIDE-Module-Specification-Version: 7.60
3
OpenIDE-Module-Specification-Version: 7.61
4
OpenIDE-Module-Localizing-Bundle: org/openide/loaders/Bundle.properties
4
OpenIDE-Module-Localizing-Bundle: org/openide/loaders/Bundle.properties
5
OpenIDE-Module-Provides: org.netbeans.modules.templates.v1_0
5
OpenIDE-Module-Provides: org.netbeans.modules.templates.v1_0
6
OpenIDE-Module-Layer: org/netbeans/modules/openide/loaders/layer.xml
6
OpenIDE-Module-Layer: org/netbeans/modules/openide/loaders/layer.xml
(-)a/openide.loaders/module-auto-deps.xml (+13 lines)
Lines 60-64 Link Here
60
            </implies>
60
            </implies>
61
        </transformation>
61
        </transformation>
62
    </transformationgroup>
62
    </transformationgroup>
63
    <transformationgroup>
64
        <description>No need for separate templates API. Merged into org.openide.loaders</description>
65
        <transformation>
66
            <trigger-dependency type="older">
67
                <module-dependency codenamebase="org.openide.loaders" spec="7.60"/>
68
            </trigger-dependency>
69
            <implies>
70
                <result>
71
                    <module-dependency codenamebase="org.netbeans.api.templates" spec="1.0"/>
72
                </result>
73
            </implies>
74
        </transformation>
75
    </transformationgroup>
63
76
64
</transformations>
77
</transformations>
(-)a/openide.loaders/nbproject/project.xml (+8 lines)
Lines 142-147 Link Here
142
                    </run-dependency>
142
                    </run-dependency>
143
                </dependency>
143
                </dependency>
144
                <dependency>
144
                <dependency>
145
                    <code-name-base>org.netbeans.api.templates</code-name-base>
146
                    <build-prerequisite/>
147
                    <compile-dependency/>
148
                    <run-dependency>
149
                        <specification-version>1.0</specification-version>
150
                    </run-dependency>
151
                </dependency>
152
                <dependency>
145
                    <code-name-base>org.openide.modules</code-name-base>
153
                    <code-name-base>org.openide.modules</code-name-base>
146
                    <build-prerequisite/>
154
                    <build-prerequisite/>
147
                    <compile-dependency/>
155
                    <compile-dependency/>
(-)a/openide.loaders/src/org/netbeans/api/templates/TemplateRegistration.java (-142 lines)
Lines 1-142 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common Development and
11
 * Distribution License("CDDL") (collectively, the "License"). You may not use
12
 * this file except in compliance with the License. You can obtain a copy of
13
 * the License at http://www.netbeans.org/cddl-gplv2.html or
14
 * nbbuild/licenses/CDDL-GPL-2-CP. See the License for the specific language
15
 * governing permissions and limitations under the License. When distributing
16
 * the software, include this License Header Notice in each file and include
17
 * the License file at nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
18
 * particular file as subject to the "Classpath" exception as provided by
19
 * Oracle in the GPL Version 2 section of the License file that accompanied
20
 * this code. If applicable, add the following below the License Header, with
21
 * the fields enclosed by brackets [] replaced by your own identifying
22
 * information: "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL or
25
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
26
 * elects to include this software in this distribution under the [CDDL or GPL
27
 * Version 2] license." If you do not indicate a single choice of license, a
28
 * recipient has the option to distribute your version of this file under
29
 * either the CDDL, the GPL Version 2 or to extend the choice of license to its
30
 * licensees as provided above. However, if you add GPL Version 2 code and
31
 * therefore, elected the GPL Version 2 license, then the option applies only
32
 * if the new code is made subject to such option by the copyright holder.
33
 *
34
 * Contributor(s):
35
 *
36
 * Portions Copyrighted 2011 Sun Microsystems, Inc.
37
 */
38
39
package org.netbeans.api.templates;
40
41
import java.lang.annotation.ElementType;
42
import java.lang.annotation.Retention;
43
import java.lang.annotation.RetentionPolicy;
44
import java.lang.annotation.Target;
45
import javax.script.ScriptEngineFactory;
46
import org.openide.WizardDescriptor.InstantiatingIterator;
47
import org.openide.loaders.TemplateWizard;
48
49
/**
50
 * Registers a template the user can select.
51
 * May be placed on a class (with a default constructor) or static method (with no arguments)
52
 * to register an {@link InstantiatingIterator} for a custom template;
53
 * or on a package to register a plain-file template with no custom behavior.
54
 * @since 7.29
55
 * @see TemplateWizard
56
 * @see TemplateRegistrations
57
 * @see <a href="@org-netbeans-modules-projectuiapi@/org/netbeans/spi/project/ui/templates/support/package-summary.html"><code>org.netbeans.spi.project.ui.templates.support</code></a>
58
 */
59
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PACKAGE})
60
@Retention(RetentionPolicy.SOURCE)
61
public @interface TemplateRegistration {
62
    
63
    /**
64
     * Subfolder in which to place the template, such as {@code Other} or {@code Project/Standard}.
65
     */
66
    String folder();
67
    
68
    /**
69
     * Optional position within {@link #folder}.
70
     */
71
    int position() default Integer.MAX_VALUE;
72
73
    /**
74
     * Special file basename to use rather than inferring one from the declaring element,
75
     * when {@link #content} is empty.
76
     * Useful for pure templates referenced from {@code PrivilegedTemplates}.
77
     */
78
    String id() default "";
79
80
    /**
81
     * File contents, as resources relative to the package of this declaration.
82
     * A nonempty list is mandatory for a template registered on a package.
83
     * For a template with a custom iterator, the content may be omitted, though it may still be specified.
84
     * <p>Normally only a single file is specified, but for a multifile data object, list the primary entry first.
85
     * <p>The file basenames (incl. extension) of the actual template files (as in {@link TemplateWizard#getTemplate})
86
     * will be taken from the basename of the content resources, though a {@code .template} suffix
87
     * may be appended to prevent template resources in a source project from being misinterpreted.
88
     * For a "pure" custom iterator with no specified content, the template basename
89
     * defaults to the FQN of the class or method defining it but with {@code -} for {@code .} characters,
90
     * e.g. {@code pkg-Class-method}, but may be overridden with {@link #id}.
91
     * <p>Example usage for a simple, single-file template (with or without custom iterator):
92
     * <pre>content="resources/empty.php"</pre>
93
     * <p>For a form template:
94
     * <pre>content={"Login.java.template", "Login.form.template"}</pre>
95
     */
96
    String[] content() default {};
97
98
    /**
99
     * Localized label for the template.
100
     * Mandatory unless {@link #content} is specified, in which case it would be defaulted by the data node.
101
     * May use the usual {@code #key} syntax.
102
     */
103
    String displayName() default "";
104
105
    /**
106
     * Icon to use for the template.
107
     * Should be an absolute resource path (no initial slash).
108
     * Mandatory unless {@link #content} is specified, in which case it would be defaulted by the data node.
109
     */
110
    String iconBase() default "";
111
112
    /**
113
     * Optional but recommended relative resource path to an HTML description of the template.
114
     * @see TemplateWizard#getDescription
115
     */
116
    String description() default "";
117
118
    /**
119
     * Optional name of a script engine to use when processing file content, such as {@code freemarker}.
120
     * @see ScriptEngineFactory#getNames
121
     */
122
    String scriptEngine() default "";
123
124
    /**
125
     * Optional list of categories interpreted by the project system.
126
     */
127
    String[] category() default {};
128
129
    /**
130
     * Set to false if the template can be instantiated without a project.
131
     * @since 7.46
132
     */
133
    boolean requireProject() default true;
134
135
    /**
136
     * Default (pre-filled) target name for the template, without extension. May
137
     * use the usual {@code #key} syntax for localization or branding.
138
     *
139
     * @since 7.56
140
     */
141
    String targetName() default "";
142
}
(-)a/openide.loaders/src/org/netbeans/api/templates/TemplateRegistrations.java (-56 lines)
Lines 1-56 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common Development and
11
 * Distribution License("CDDL") (collectively, the "License"). You may not use
12
 * this file except in compliance with the License. You can obtain a copy of
13
 * the License at http://www.netbeans.org/cddl-gplv2.html or
14
 * nbbuild/licenses/CDDL-GPL-2-CP. See the License for the specific language
15
 * governing permissions and limitations under the License. When distributing
16
 * the software, include this License Header Notice in each file and include
17
 * the License file at nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
18
 * particular file as subject to the "Classpath" exception as provided by
19
 * Oracle in the GPL Version 2 section of the License file that accompanied
20
 * this code. If applicable, add the following below the License Header, with
21
 * the fields enclosed by brackets [] replaced by your own identifying
22
 * information: "Portions Copyrighted [year] [name of copyright owner]"
23
 *
24
 * If you wish your version of this file to be governed by only the CDDL or
25
 * only the GPL Version 2, indicate your decision by adding "[Contributor]
26
 * elects to include this software in this distribution under the [CDDL or GPL
27
 * Version 2] license." If you do not indicate a single choice of license, a
28
 * recipient has the option to distribute your version of this file under
29
 * either the CDDL, the GPL Version 2 or to extend the choice of license to its
30
 * licensees as provided above. However, if you add GPL Version 2 code and
31
 * therefore, elected the GPL Version 2 license, then the option applies only
32
 * if the new code is made subject to such option by the copyright holder.
33
 *
34
 * Contributor(s):
35
 *
36
 * Portions Copyrighted 2011 Sun Microsystems, Inc.
37
 */
38
39
package org.netbeans.api.templates;
40
41
import java.lang.annotation.ElementType;
42
import java.lang.annotation.Retention;
43
import java.lang.annotation.RetentionPolicy;
44
import java.lang.annotation.Target;
45
46
/**
47
 * May be used to register multiple plain-file {@link TemplateRegistration}s.
48
 * Use on a package for simple templates, or on an iterator for multiple variants of a template
49
 * with different {@link TemplateRegistration#content}.
50
 * @since 7.29
51
 */
52
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PACKAGE})
53
@Retention(RetentionPolicy.SOURCE)
54
public @interface TemplateRegistrations {
55
    TemplateRegistration[] value();
56
}
(-)a/openide.loaders/src/org/netbeans/modules/templates/DesktopTemplateAttributes.java (+76 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2014 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2014 Sun Microsystems, Inc.
41
 */
42
package org.netbeans.modules.templates;
43
44
import java.text.DateFormat;
45
import java.util.Date;
46
import java.util.HashMap;
47
import java.util.Map;
48
import org.netbeans.api.templates.CreateDescriptor;
49
import org.netbeans.api.templates.CreateFromTemplateAttributes;
50
import org.openide.util.lookup.ServiceProvider;
51
52
/**
53
 * Compatible implementation for desktop applications. Provides username and
54
 * date/time format based on JRE properties/defaults.
55
 * 
56
 * @author sdedic
57
 */
58
@ServiceProvider(service = CreateFromTemplateAttributes.class, position = Integer.MIN_VALUE)
59
public class DesktopTemplateAttributes implements CreateFromTemplateAttributes {
60
    @Override
61
    public Map<String, ?> attributesFor(CreateDescriptor desc) {
62
        Map<String, Object> vals = new HashMap<String, Object>();
63
        Date d = new Date();
64
        vals.put("user", // NOI18N
65
                System.getProperty("user.name") // NOI18N
66
        );
67
        vals.put("date",  // NOI18N
68
            DateFormat.getDateInstance(DateFormat.DEFAULT, desc.getLocale()).format(d)
69
        );
70
        vals.put("time",  // NOI18N
71
            DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, desc.getLocale()).format(d)
72
        );
73
        
74
        return vals;
75
    }
76
}
(-)a/openide.loaders/src/org/netbeans/modules/templates/ScriptingCreateFromTemplateHandler.java (-154 lines)
Lines 1-154 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * Contributor(s):
28
 *
29
 * The Original Software is NetBeans. The Initial Developer of the Original
30
 * Software is Sun Microsystems, Inc.
31
 *
32
 * Portions Copyrighted 2007 Sun Microsystems, Inc.
33
 */
34
35
package org.netbeans.modules.templates;
36
37
import java.io.IOException;
38
import java.io.InputStreamReader;
39
import java.io.OutputStreamWriter;
40
import java.io.PrintWriter;
41
import java.io.Reader;
42
import java.io.Writer;
43
import java.nio.charset.Charset;
44
import java.util.Map;
45
import javax.script.Bindings;
46
import javax.script.ScriptContext;
47
import javax.script.ScriptEngine;
48
import javax.script.ScriptEngineManager;
49
import javax.script.ScriptException;
50
import javax.swing.text.PlainDocument;
51
import org.netbeans.api.queries.FileEncodingQuery;
52
import org.openide.filesystems.FileObject;
53
import org.openide.filesystems.FileUtil;
54
import org.openide.loaders.CreateFromTemplateHandler;
55
import org.openide.text.IndentEngine;
56
import org.openide.util.Lookup;
57
import org.openide.util.lookup.ServiceProvider;
58
59
60
/** Processes templates that have associated attribute
61
* with name of the scripting engine.
62
*
63
* @author  Jaroslav Tulach
64
*/
65
@ServiceProvider(service=CreateFromTemplateHandler.class)
66
public class ScriptingCreateFromTemplateHandler extends CreateFromTemplateHandler {
67
68
    public static final String SCRIPT_ENGINE_ATTR = "javax.script.ScriptEngine";
69
    
70
    private static ScriptEngineManager manager;
71
    
72
    private static final String ENCODING_PROPERTY_NAME = "encoding"; //NOI18N
73
    
74
    @Override
75
    protected boolean accept(FileObject orig) {
76
        return engine(orig) != null;
77
    }
78
79
    @Override
80
    protected FileObject createFromTemplate(FileObject template, FileObject f,
81
                                            String name,
82
                                            Map<String, Object> values) throws IOException {
83
        boolean noExt = Boolean.TRUE.equals(values.get(FREE_FILE_EXTENSION)) && name.indexOf('.') != -1;
84
        
85
        String extWithDot;
86
        if (noExt) {
87
            extWithDot = null;
88
        } else {
89
            extWithDot = '.' + template.getExt();
90
            if (name.endsWith(extWithDot)) { // Test whether the extension happens to be there already
91
                // And remove it if yes, it will be appended to the unique name.
92
                name = name.substring(0, name.length() - extWithDot.length());
93
            }
94
        }
95
        
96
        String nameUniq = FileUtil.findFreeFileName(f, name, noExt ? null : template.getExt());
97
        FileObject output = FileUtil.createData(f, noExt ? nameUniq : nameUniq + extWithDot);
98
        Charset targetEnc = FileEncodingQuery.getEncoding(output);
99
        Charset sourceEnc = FileEncodingQuery.getEncoding(template);
100
        
101
        ScriptEngine eng = engine(template);
102
        Bindings bind = eng.getContext().getBindings(ScriptContext.ENGINE_SCOPE);
103
        bind.putAll(values);
104
        
105
        if(!values.containsKey(ENCODING_PROPERTY_NAME)) {
106
            bind.put(ENCODING_PROPERTY_NAME, targetEnc.name());
107
        }
108
        
109
        Writer w = null;
110
        Reader is = null;
111
        try {
112
            w = new OutputStreamWriter(output.getOutputStream(), targetEnc);
113
            
114
            IndentEngine format = IndentEngine.find(template.getMIMEType());
115
            if (format != null) {
116
                PlainDocument doc = new PlainDocument();
117
                doc.putProperty(PlainDocument.StreamDescriptionProperty, template);
118
                w = format.createWriter(doc, 0, w);
119
            }
120
            
121
            
122
            eng.getContext().setWriter(new PrintWriter(w));
123
            //eng.getContext().setBindings(bind, ScriptContext.ENGINE_SCOPE);
124
            eng.getContext().setAttribute(FileObject.class.getName(), template, ScriptContext.ENGINE_SCOPE);
125
            eng.getContext().setAttribute(ScriptEngine.FILENAME, template.getNameExt(), ScriptContext.ENGINE_SCOPE);
126
            is = new InputStreamReader(template.getInputStream(), sourceEnc);
127
            eng.eval(is);
128
        }catch (ScriptException ex) {
129
            IOException io = new IOException(ex.getMessage(), ex);
130
            throw io;
131
        } finally {
132
            if (w != null) w.close();
133
            if (is != null) is.close();
134
        }
135
        return output;
136
    }
137
    
138
    private static ScriptEngine engine(FileObject fo) {
139
        Object obj = fo.getAttribute(SCRIPT_ENGINE_ATTR); // NOI18N
140
        if (obj instanceof ScriptEngine) {
141
            return (ScriptEngine)obj;
142
        }
143
        if (obj instanceof String) {
144
            synchronized (ScriptingCreateFromTemplateHandler.class) {
145
                if (manager == null) {
146
                    ClassLoader loader = Lookup.getDefault().lookup(ClassLoader.class);
147
                    manager = new ScriptEngineManager(loader != null ? loader : Thread.currentThread().getContextClassLoader());
148
                }
149
            }
150
            return manager.getEngineByName((String) obj);
151
        }
152
        return null;
153
    }
154
}
(-)a/openide.loaders/src/org/netbeans/modules/templates/TemplateProcessor.java (-51 / +9 lines)
Lines 38-45 Link Here
38
38
39
package org.netbeans.modules.templates;
39
package org.netbeans.modules.templates;
40
40
41
import java.net.URI;
42
import java.net.URISyntaxException;
43
import java.util.Arrays;
41
import java.util.Arrays;
44
import java.util.HashSet;
42
import java.util.HashSet;
45
import java.util.Set;
43
import java.util.Set;
Lines 58-63 Link Here
58
import org.openide.filesystems.annotations.LayerGeneratingProcessor;
56
import org.openide.filesystems.annotations.LayerGeneratingProcessor;
59
import org.openide.util.lookup.ServiceProvider;
57
import org.openide.util.lookup.ServiceProvider;
60
58
59
/**
60
 * The processor was split into two parts. The part which defines how the template
61
 * annotation fields will be translated into the XML layer is defined in {@code openide.filesystems.templates}
62
 * module. This Processor implementation binds the template to a Wizard Iterator, if the annotation is on
63
 * an executable method.
64
 * 
65
 * @author sdedic
66
 */
61
@ServiceProvider(service=Processor.class)
67
@ServiceProvider(service=Processor.class)
62
@SupportedSourceVersion(SourceVersion.RELEASE_7)
68
@SupportedSourceVersion(SourceVersion.RELEASE_7)
63
public class TemplateProcessor extends LayerGeneratingProcessor {
69
public class TemplateProcessor extends LayerGeneratingProcessor {
Lines 86-92 Link Here
86
                process(e, t);
92
                process(e, t);
87
            }
93
            }
88
        }
94
        }
89
        return true;
95
        return false;
90
    }
96
    }
91
97
92
    private void process(Element e, TemplateRegistration t) throws LayerGenerationException {
98
    private void process(Element e, TemplateRegistration t) throws LayerGenerationException {
Lines 110-170 Link Here
110
        }
116
        }
111
        String folder = "Templates/" + t.folder() + '/';
117
        String folder = "Templates/" + t.folder() + '/';
112
        LayerBuilder.File f = builder.file(folder + basename);
118
        LayerBuilder.File f = builder.file(folder + basename);
113
        f.boolvalue("template", true);
114
        f.position(t.position());
115
        if (!t.displayName().isEmpty()) {
116
            f.bundlevalue("displayName", t.displayName());
117
        }
118
        if (!t.iconBase().isEmpty()) {
119
            builder.validateResource(t.iconBase(), e, t, "iconBase", true);
120
            f.stringvalue("iconBase", t.iconBase());
121
        } else if (t.content().length == 0) {
122
            throw new LayerGenerationException("Must specify iconBase if content is not specified", e, processingEnv, t);
123
        }
124
        if (!t.description().isEmpty()) {
125
            f.urlvalue("instantiatingWizardURL", contentURI(e, t.description(), builder, t, "description"));
126
        }
127
        if (e.getKind() != ElementKind.PACKAGE) {
119
        if (e.getKind() != ElementKind.PACKAGE) {
128
            f.instanceAttribute("instantiatingIterator", InstantiatingIterator.class);
120
            f.instanceAttribute("instantiatingIterator", InstantiatingIterator.class);
129
        }
121
        }
130
        if (t.content().length > 0) {
131
            f.url(contentURI(e, t.content()[0], builder, t, "content").toString());
132
            for (int i = 1; i < t.content().length; i++) {
133
                builder.file(folder + basename(t.content()[i])).url(contentURI(e, t.content()[i], builder, t, "content").toString()).position(0).write();
134
            }
135
        }
136
        if (!t.scriptEngine().isEmpty()) {
137
            f.stringvalue(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, t.scriptEngine());
138
        }
139
        if (t.category().length > 0) {
140
            StringBuilder sb = new StringBuilder();
141
            for (String c : t.category()) {
142
                if (sb.length() > 0) {
143
                    sb.append(',');
144
                }
145
                sb.append(c);
146
            }
147
            f.stringvalue("templateCategory", sb.toString());
148
        }
149
        f.boolvalue("requireProject", t.requireProject());
150
        if (!t.targetName().trim().isEmpty()) {
151
            f.bundlevalue("targetName", t.targetName());                //NOI18N
152
        }
153
        f.write();
122
        f.write();
154
    }
123
    }
155
124
156
    private static String basename(String relativeResource) {
125
    private static String basename(String relativeResource) {
157
        return relativeResource.replaceFirst(".+/", "").replaceFirst("[.]template$", "");
126
        return relativeResource.replaceFirst(".+/", "").replaceFirst("[.]template$", "");
158
    }
127
    }
159
160
    private URI contentURI(Element e, String relativePath, LayerBuilder builder, TemplateRegistration t, String annotationMethod) throws LayerGenerationException {
161
        String path = LayerBuilder.absolutizeResource(e, relativePath);
162
        builder.validateResource(path, e, t, annotationMethod, false);
163
        try {
164
            return new URI("nbresloc", "/" + path, null).normalize();
165
        } catch (URISyntaxException x) {
166
            throw new LayerGenerationException("could not translate " + path, e, processingEnv, t);
167
        }
168
    }
169
170
}
128
}
(-)a/openide.loaders/src/org/openide/actions/SaveAsTemplateAction.java (-2 / +3 lines)
Lines 50-56 Link Here
50
import java.util.HashMap;
50
import java.util.HashMap;
51
import java.util.Map;
51
import java.util.Map;
52
import java.util.Map.Entry;
52
import java.util.Map.Entry;
53
import org.netbeans.modules.templates.ScriptingCreateFromTemplateHandler;
54
import org.openide.cookies.SaveCookie;
53
import org.openide.cookies.SaveCookie;
55
import org.openide.filesystems.FileObject;
54
import org.openide.filesystems.FileObject;
56
import org.openide.loaders.*;
55
import org.openide.loaders.*;
Lines 136-141 Link Here
136
    protected boolean asynchronous() {
135
    protected boolean asynchronous() {
137
        return false;
136
        return false;
138
    }
137
    }
138
    
139
    static final String SCRIPT_ENGINE_ATTR = "javax.script.ScriptEngine"; // NOI18N
139
140
140
    /** Performs the work of creating a new template */
141
    /** Performs the work of creating a new template */
141
    private void createNewTemplate(DataObject source,
142
    private void createNewTemplate(DataObject source,
Lines 156-162 Link Here
156
            newTemplate.setTemplate(true);
157
            newTemplate.setTemplate(true);
157
            if (templateSample == null) {
158
            if (templateSample == null) {
158
                // a fallback if no template sample found
159
                // a fallback if no template sample found
159
                newTemplate.getPrimaryFile().setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "freemarker"); // NOI18N
160
                newTemplate.getPrimaryFile().setAttribute(SCRIPT_ENGINE_ATTR, "freemarker"); // NOI18N
160
            } else {
161
            } else {
161
                setTemplateAttributes (newTemplate.getPrimaryFile (), getAttributes (templateSample.getPrimaryFile ()));
162
                setTemplateAttributes (newTemplate.getPrimaryFile (), getAttributes (templateSample.getPrimaryFile ()));
162
            }
163
            }
(-)a/openide.loaders/src/org/openide/loaders/CreateFromTemplateAttributesProvider.java (+9 lines)
Lines 41-49 Link Here
41
 * and allows anyone provide additional parameters to each {@link CreateFromTemplateHandler}s
41
 * and allows anyone provide additional parameters to each {@link CreateFromTemplateHandler}s
42
 * when a template is instantiating.
42
 * when a template is instantiating.
43
 * Read more in the <a href="@TOP@/architecture-summary.html#script">howto document</a>.
43
 * Read more in the <a href="@TOP@/architecture-summary.html#script">howto document</a>.
44
 * <p/>
45
 * Since templating system need not to depend on Data Systems APIs, the relevant interfaces
46
 * were moved to the {@code openide.filesystems.templates} module. This interface has been kept
47
 * for backward compatibility and DataSystems provide a compatibility bridge, which allows
48
 * old providers to participate. Module writers are encouraged to implement 
49
 * {@link org.netbeans.api.templates.CreateFromTemplateAttributes}
50
 * instead.
44
 * 
51
 * 
45
 * @author Jaroslav Tulach
52
 * @author Jaroslav Tulach
46
 * @since 6.3
53
 * @since 6.3
54
 * @since deprecated from 7.59
55
 * @deprecated Use {@link CreateFromTemplateAttributes} in {@code openide.filesystems.templates} instead.
47
 */
56
 */
48
public interface CreateFromTemplateAttributesProvider {
57
public interface CreateFromTemplateAttributesProvider {
49
    /** Called when a template is about to be instantiated to provide additional
58
    /** Called when a template is about to be instantiated to provide additional
(-)a/openide.loaders/src/org/openide/loaders/CreateFromTemplateHandler.java (-2 / +28 lines)
Lines 35-41 Link Here
35
package org.openide.loaders;
35
package org.openide.loaders;
36
36
37
import java.io.IOException;
37
import java.io.IOException;
38
import java.util.Collections;
39
import java.util.List;
38
import java.util.Map;
40
import java.util.Map;
41
import org.netbeans.api.templates.CreateDescriptor;
39
import org.openide.filesystems.FileObject;
42
import org.openide.filesystems.FileObject;
40
43
41
/** This is an interface for <q>smart templating</q> that allows
44
/** This is an interface for <q>smart templating</q> that allows
Lines 43-53 Link Here
43
 * and handle them themselves. The NetBeans IDE provides default
46
 * and handle them themselves. The NetBeans IDE provides default
44
 * implementation that allows use of Freemarker templating engine.
47
 * implementation that allows use of Freemarker templating engine.
45
 * Read more in the <a href="@TOP@/architecture-summary.html#script">howto document</a>.
48
 * Read more in the <a href="@TOP@/architecture-summary.html#script">howto document</a>.
46
 *
49
 * <p/>
50
 * This SPI is now <b>deprecated</b> and serves just a backward compatilibity SPI adapter
51
 * which allows the template API to work with legacy handlers. The templating SPI is delegated
52
 * to the original handler methods.
53
 * 
47
 * @author Jaroslav Tulach
54
 * @author Jaroslav Tulach
48
 * @since 6.1
55
 * @since 6.1
56
 * @deprecated in 7.59. Use {@link org.netbeans.api.templates.CreateFromTemplateHandler} instead.
49
 */
57
 */
50
public abstract class CreateFromTemplateHandler {
58
public abstract class CreateFromTemplateHandler extends org.netbeans.api.templates.CreateFromTemplateHandler {
59
    
60
    @Override
61
    public boolean accept(CreateDescriptor desc) {
62
        return accept(desc.getTemplate());
63
    }
64
65
    @Override
66
    protected List<FileObject> createFromTemplate(CreateDescriptor desc) throws IOException {
67
        return Collections.singletonList(
68
                createFromTemplate(
69
                        desc.getTemplate(),
70
                        desc.getTarget(),
71
                        desc.getName(),
72
                        desc.getParameters()
73
                )
74
        );
75
    }
76
    
51
    /** Method that allows a handler to reject a file. If all handlers
77
    /** Method that allows a handler to reject a file. If all handlers
52
     * reject a file, regular processing defined in {@link DataObject#handleCreateFromTemplate}
78
     * reject a file, regular processing defined in {@link DataObject#handleCreateFromTemplate}
53
     * is going to take place.
79
     * is going to take place.
(-)a/openide.loaders/src/org/openide/loaders/DataObject.java (+13 lines)
Lines 1601-1606 Link Here
1601
            }
1601
            }
1602
        }
1602
        }
1603
        
1603
        
1604
        public static Map<String, Object> getCallParameters(String name) {
1605
            CreateAction c  = CURRENT.get();
1606
            if (c == null || c.param == null) {
1607
                return Collections.emptyMap();
1608
            }
1609
            return Collections.unmodifiableMap(c.param);
1610
        }
1611
        
1612
        static String getOrigName() {
1613
            CreateAction c  = CURRENT.get();
1614
            return c == null ? null : c.name;
1615
        }
1616
        
1604
        public static Map<String,Object> findParameters(String name) {
1617
        public static Map<String,Object> findParameters(String name) {
1605
            CreateAction c  = CURRENT.get();
1618
            CreateAction c  = CURRENT.get();
1606
            if (c == null) {
1619
            if (c == null) {
(-)a/openide.loaders/src/org/openide/loaders/FileEntry.java (-76 / +12 lines)
Lines 45-52 Link Here
45
package org.openide.loaders;
45
package org.openide.loaders;
46
46
47
import java.io.*;
47
import java.io.*;
48
import java.util.List;
49
import org.netbeans.api.templates.FileBuilder;
48
import org.openide.filesystems.*;
50
import org.openide.filesystems.*;
49
import org.openide.util.Lookup;
50
import org.openide.util.NbBundle;
51
import org.openide.util.NbBundle;
51
52
52
/** Entry that works with plain files. Copies, moves,
53
/** Entry that works with plain files. Copies, moves,
Lines 149-180 Link Here
149
    * @param f the folder to create instance in
150
    * @param f the folder to create instance in
150
    * @param name name of the file or null if it should be choosen automaticly
151
    * @param name name of the file or null if it should be choosen automaticly
151
    */
152
    */
153
    @Override
152
    public FileObject createFromTemplate (FileObject f, String name) throws IOException {
154
    public FileObject createFromTemplate (FileObject f, String name) throws IOException {
153
        if (name == null) {
155
        FileObject fo = FileBuilder.createFromTemplate(getFile(), f, name, 
154
            name = FileUtil.findFreeFileName(
156
                DataObject.CreateAction.getCallParameters(name), 
155
                       f,
157
                FileBuilder.Mode.COPY);
156
                       getFile ().getName (), getFile ().getExt ()
157
                   );
158
        }
159
        
160
        
161
        FileObject fo = null;
162
        for (CreateFromTemplateHandler h : Lookup.getDefault().lookupAll(CreateFromTemplateHandler.class)) {
163
            if (h.accept(getFile())) {
164
                fo = h.createFromTemplate(getFile(), f, name,
165
                    DataObject.CreateAction.enhanceParameters(
166
                        DataObject.CreateAction.findParameters(name),
167
                        name, getFile().getExt()));
168
                assert fo != null;
169
                break;
170
            }
171
        }
172
        
173
        if (fo == null) {
174
            fo = getFile().copy (f, name, getFile().getExt ());
175
        }
176
        
177
        
178
        // unmark template state
158
        // unmark template state
179
        DataObject.setTemplate (fo, false);
159
        DataObject.setTemplate (fo, false);
180
160
Lines 204-268 Link Here
204
        * @param f the folder to create instance in
184
        * @param f the folder to create instance in
205
        * @param name name of the file or null if it should be choosen automaticly
185
        * @param name name of the file or null if it should be choosen automaticly
206
        */
186
        */
187
        @Override
188
        @SuppressWarnings("AssignmentToMethodParameter")
207
        public FileObject createFromTemplate (FileObject f, String name) throws IOException {
189
        public FileObject createFromTemplate (FileObject f, String name) throws IOException {
208
            String ext = getFile ().getExt ();
190
            String ext = getFile ().getExt ();
209
210
            if (name == null) {
191
            if (name == null) {
211
                name = FileUtil.findFreeFileName(
192
                name = FileUtil.findFreeFileName(
212
                           f,
193
                           f,
213
                           getFile ().getName (), ext
194
                           getFile ().getName (), ext
214
                       );
195
                       );
215
            }
196
            }
216
            
217
            FileObject fo = null;
218
            for (CreateFromTemplateHandler h : Lookup.getDefault().lookupAll(CreateFromTemplateHandler.class)) {
219
                if (h.accept(getFile())) {
220
                    fo = h.createFromTemplate(
221
                        getFile(), f, name,
222
                        DataObject.CreateAction.enhanceParameters(
223
                            DataObject.CreateAction.findParameters(name),
224
                            name, getFile().getExt()));
225
                    assert fo != null;
226
                    break;
227
                }
228
            }
229
230
            if (fo != null) {
231
                // unmark template state
232
                DataObject.setTemplate (fo, false);
233
                return fo;
234
            }
235
            
236
            fo = f.createData (name, ext);
237
238
            java.text.Format frm = createFormat (f, name, ext);
197
            java.text.Format frm = createFormat (f, name, ext);
239
198
            List<FileObject> fos = new FileBuilder(getFile(), f).name(name).
240
            BufferedReader r = new BufferedReader (new InputStreamReader (getFile ().getInputStream ()));
199
                    withParameters(DataObject.CreateAction.getCallParameters(name)).
241
            try {
200
                    useFormat(frm).build();
242
                FileLock lock = fo.lock ();
201
            FileObject fo = fos.get(0);
243
                try {
244
                    BufferedWriter w = new BufferedWriter (new OutputStreamWriter (fo.getOutputStream (lock)));
245
246
                    try {
247
                        String current;
248
                        while ((current = r.readLine ()) != null) {
249
                            w.write (frm.format (current));
250
                            // Cf. #7061.
251
                            w.newLine ();
252
                        }
253
                    } finally {
254
                        w.close ();
255
                    }
256
                } finally {
257
                    lock.releaseLock ();
258
                }
259
            } finally {
260
                r.close ();
261
            }
262
263
            // copy attributes
264
            FileUtil.copyAttributes (getFile (), fo);
265
266
            // unmark template state
202
            // unmark template state
267
            DataObject.setTemplate (fo, false);
203
            DataObject.setTemplate (fo, false);
268
204
(-)a/openide.loaders/src/org/openide/loaders/FileTemplateHandlerBridge.java (+104 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2014 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2014 Sun Microsystems, Inc.
41
 */
42
package org.openide.loaders;
43
44
import java.util.Collection;
45
import java.util.Collections;
46
import java.util.HashMap;
47
import java.util.Map;
48
import org.netbeans.api.templates.CreateDescriptor;
49
import org.openide.filesystems.FileObject;
50
import org.netbeans.api.templates.CreateFromTemplateAttributes;
51
import org.openide.util.Exceptions;
52
import org.openide.util.Lookup;
53
import org.openide.util.lookup.ServiceProvider;
54
55
/**
56
 * Bridges loader-based handler registration to the fileobject-based one. Provides
57
 * compatibility with NB &lt;= 8.0.1. New clients are encouraged to use the new
58
 * {@link CreateFromTemplateAttributes} interface directly.
59
 * 
60
 * @author sdedic
61
 */
62
@ServiceProvider(service = CreateFromTemplateAttributes.class, position = Integer.MIN_VALUE)
63
public class FileTemplateHandlerBridge implements CreateFromTemplateAttributes {
64
    private Lookup.Result<CreateFromTemplateAttributesProvider> providers;
65
66
    public FileTemplateHandlerBridge() {
67
        providers = Lookup.getDefault().lookupResult(CreateFromTemplateAttributesProvider.class);
68
    }
69
    
70
    @Override
71
    public Map<String, ?> attributesFor(CreateDescriptor desc) {
72
        FileObject template = desc.getTemplate();
73
        FileObject target = desc.getTarget();
74
        Collection<? extends CreateFromTemplateAttributesProvider> c = providers.allInstances();
75
        if (c.isEmpty()) {
76
            return Collections.emptyMap();
77
        }
78
        DataObject d;
79
        DataFolder fld;
80
        
81
        try {
82
            d = DataObject.find(template);
83
            fld = DataFolder.findFolder(target);
84
        } catch (DataObjectNotFoundException ex) {
85
            // ???
86
            Exceptions.printStackTrace(ex);
87
            return Collections.emptyMap();
88
        }
89
        HashMap<String,Object> all = new HashMap<String,Object>();
90
        for (CreateFromTemplateAttributesProvider p : c) {
91
            // must use getName, since some features may rely on that null propagates to the Provider 
92
            // if the initiator does not specify a name.
93
            Map<String, ? extends Object> map = p.attributesFor(d, fld, DataObject.CreateAction.getOrigName());
94
            if (map != null) {
95
                for (Map.Entry<String,? extends Object> e : map.entrySet()) {
96
                    all.put(e.getKey(), e.getValue());
97
                }
98
            }
99
        }
100
        
101
        return all;
102
    }
103
104
}
(-)a/openide.loaders/src/org/openide/loaders/MultiDataObject.java (-35 / +8 lines)
Lines 49-72 Link Here
49
import java.beans.PropertyVetoException;
49
import java.beans.PropertyVetoException;
50
import java.io.*;
50
import java.io.*;
51
import java.lang.ref.WeakReference;
51
import java.lang.ref.WeakReference;
52
import java.lang.reflect.Method;
53
import java.util.*;
52
import java.util.*;
54
import java.util.concurrent.Callable;
55
import java.util.logging.*;
53
import java.util.logging.*;
56
import javax.swing.event.*;
54
import javax.swing.event.*;
57
import org.netbeans.api.actions.Editable;
55
import org.netbeans.api.actions.Editable;
58
import org.netbeans.api.actions.Openable;
56
import org.netbeans.api.actions.Openable;
57
import org.netbeans.api.templates.FileBuilder;
59
import org.openide.cookies.CloseCookie;
58
import org.openide.cookies.CloseCookie;
60
import org.openide.cookies.EditorCookie;
59
import org.openide.cookies.EditorCookie;
61
import org.openide.cookies.LineCookie;
60
import org.openide.cookies.LineCookie;
62
import org.openide.cookies.PrintCookie;
63
import org.openide.filesystems.*;
61
import org.openide.filesystems.*;
64
import org.openide.nodes.*;
62
import org.openide.nodes.*;
65
import org.openide.nodes.Node.Cookie;
66
import org.openide.text.CloneableEditor;
63
import org.openide.text.CloneableEditor;
67
import org.openide.text.CloneableEditorSupport;
68
import org.openide.text.CloneableEditorSupport.Pane;
69
import org.openide.text.DataEditorSupport;
70
import org.openide.util.*;
64
import org.openide.util.*;
71
65
72
/** Provides support for handling of data objects with multiple files.
66
/** Provides support for handling of data objects with multiple files.
Lines 876-896 Link Here
876
        }
870
        }
877
871
878
        FileObject pf = null;
872
        FileObject pf = null;
879
        Map<String,Object> params = null;
873
        Map<String, Object> params = CreateAction.getCallParameters(name);
880
        for (CreateFromTemplateHandler h : Lookup.getDefault().lookupAll(CreateFromTemplateHandler.class)) {
874
        pf = FileBuilder.createFromTemplate(getPrimaryFile(), df.getPrimaryFile(), name, params, FileBuilder.Mode.FAIL);
881
            FileObject current = getPrimaryEntry().getFile();
875
        if (pf == null) {
882
            if (h.accept(current)) {
883
                if (params == null) {
884
                    params = DataObject.CreateAction.findParameters(name);
885
                }
886
                pf = h.createFromTemplate(current, df.getPrimaryFile(), name,
887
                    DataObject.CreateAction.enhanceParameters(params, name, current.getExt())
888
                );
889
                assert pf != null;
890
                break;
891
            }
892
        }
893
        if (params == null) {
894
            // do the regular creation
876
            // do the regular creation
895
            pf = getPrimaryEntry().createFromTemplate (df.getPrimaryFile (), name);
877
            pf = getPrimaryEntry().createFromTemplate (df.getPrimaryFile (), name);
896
        }
878
        }
Lines 899-918 Link Here
899
        Iterator<Entry> it = secondaryEntries().iterator();
881
        Iterator<Entry> it = secondaryEntries().iterator();
900
        NEXT_ENTRY: while (it.hasNext ()) {
882
        NEXT_ENTRY: while (it.hasNext ()) {
901
            Entry entry = it.next();
883
            Entry entry = it.next();
902
            for (CreateFromTemplateHandler h : Lookup.getDefault().lookupAll(CreateFromTemplateHandler.class)) {
884
            FileObject current = entry.getFile();
903
                FileObject current = entry.getFile();
885
            FileObject fo = FileBuilder.createFromTemplate(current, df.getPrimaryFile(), name, params, FileBuilder.Mode.FAIL);
904
                if (h.accept(current)) {
886
            if (fo == null) {
905
                    if (params == null) {
887
                entry.createFromTemplate (df.getPrimaryFile (), name);
906
                        params = DataObject.CreateAction.findParameters(name);
907
                    }
908
                    FileObject fo = h.createFromTemplate(current, df.getPrimaryFile(), name, 
909
                        DataObject.CreateAction.enhanceParameters(params, name, current.getExt())
910
                    );
911
                    assert fo != null;
912
                    continue NEXT_ENTRY;
913
                }
914
            }
888
            }
915
            entry.createFromTemplate (df.getPrimaryFile (), name);
916
        }
889
        }
917
        
890
        
918
        try {
891
        try {
(-)a/openide.loaders/test/unit/src/org/netbeans/modules/templates/Bug138973Test.java (-264 lines)
Lines 1-264 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2010 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2008 Sun Microsystems, Inc.
41
 */
42
43
package org.netbeans.modules.templates;
44
45
import java.util.Enumeration;
46
import org.openide.loaders.*;
47
import java.io.BufferedReader;
48
import java.io.BufferedWriter;
49
import java.io.ByteArrayInputStream;
50
import java.io.IOException;
51
import java.io.InputStream;
52
import java.io.InputStreamReader;
53
import java.io.OutputStream;
54
import java.io.OutputStreamWriter;
55
import java.io.Reader;
56
import java.io.Writer;
57
import java.nio.ByteBuffer;
58
import java.nio.CharBuffer;
59
import java.nio.charset.Charset;
60
import java.nio.charset.CharsetDecoder;
61
import java.nio.charset.CharsetEncoder;
62
import java.nio.charset.CoderResult;
63
import java.util.Map;
64
import org.netbeans.api.queries.FileEncodingQuery;
65
import org.netbeans.junit.MockServices;
66
import org.netbeans.junit.NbTestCase;
67
import org.netbeans.modules.openide.loaders.DataObjectEncodingQueryImplementation;
68
import org.netbeans.spi.queries.FileEncodingQueryImplementation;
69
import org.openide.filesystems.FileObject;
70
import org.openide.filesystems.FileUtil;
71
import org.openide.util.Enumerations;
72
import org.openide.util.Lookup;
73
import org.openide.util.lookup.Lookups;
74
75
/**
76
 *
77
 * @author  Marian Petras
78
 */
79
public class Bug138973Test extends NbTestCase {
80
81
    private static final String TESTING_TEXT = "print('This is a testing text.')";
82
    private static final TestCharset TEST_CHARSET = new TestCharset();
83
    private static final String EXT = ".test";
84
    private static final String TEMPLATE_NAME = "Bug138973TestTemplate";
85
    private static final String TEMPLATE_NAME_EXT = TEMPLATE_NAME + EXT;
86
    private static final String TESTFILE_NAME = "testfile";
87
    private static final String TESTFILE_NAME_EXT = TESTFILE_NAME + EXT;
88
89
    public Bug138973Test(String n) {
90
        super(n);
91
    }
92
93
    public void testBug() throws Exception {
94
        MockServices.setServices(Pool.class, DataObjectEncodingQueryImplementation.class);
95
        FileUtil.setMIMEType("test", "text/test");
96
97
        FileUtil.createData(FileUtil.getConfigRoot(), "Editors/text/test/" + TestEncoding.class.getName().replace('.', '-') + ".instance");
98
99
        FileObject root = FileUtil.createMemoryFileSystem().getRoot();
100
        FileObject templatesFolder = root.createFolder("templates");
101
        assert templatesFolder != null;
102
        FileObject templateFile = FileUtil.createData(templatesFolder,
103
                                                      TEMPLATE_NAME_EXT);
104
        templateFile.setAttribute ("template", Boolean.TRUE);
105
        templateFile.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
106
        byte[] templateBytes = TESTING_TEXT.getBytes("ISO-8859-1");
107
        InputStream source = new ByteArrayInputStream(templateBytes);
108
        OutputStream target = templateFile.getOutputStream();
109
        FileUtil.copy(source, target);
110
        target.close();
111
        source.close();
112
        assert templateFile.getSize() != 0L;
113
        templateFile.setAttribute("template", Boolean.TRUE);
114
115
        assertEquals("text/test", templateFile.getMIMEType());
116
117
        assertEquals("No Decoder yet", 0, TestCharset.newDecoder);
118
        DataObject templateDataObj = DataObject.find(templateFile);
119
        DataObject newDataObj= templateDataObj.createFromTemplate(
120
                                                    DataFolder.findFolder(root),
121
                                                    TESTFILE_NAME);
122
123
        assertTrue("Decoder created", TestCharset.newDecoder >= 1);
124
    }
125
126
    public static final class SimpleTemplateHandler extends CreateFromTemplateHandler {
127
        @Override
128
        protected boolean accept(FileObject orig) {
129
            return true;
130
        }
131
        @Override
132
        protected FileObject createFromTemplate(FileObject template,
133
                                                FileObject targetFolder,
134
                                                String name,
135
                                                Map<String, Object> parameters) throws IOException {
136
            String nameUniq = FileUtil.findFreeFileName(targetFolder, name, template.getExt());
137
            FileObject newFile = FileUtil.createData(targetFolder, nameUniq + '.' + template.getExt());
138
139
            Charset templateEnc = FileEncodingQuery.getEncoding(template);
140
            Charset newFileEnc = FileEncodingQuery.getEncoding(newFile);
141
142
            InputStream is = template.getInputStream();
143
            Reader reader = new BufferedReader(new InputStreamReader(is, templateEnc));
144
            OutputStream os = newFile.getOutputStream();
145
            Writer writer = new BufferedWriter(new OutputStreamWriter(os, newFileEnc));
146
            int cInt;
147
            while ((cInt = reader.read()) != -1) {
148
                writer.write(cInt);
149
            }
150
            writer.close();
151
            reader.close();
152
153
            return newFile;
154
        }
155
    }
156
157
    public static final class SimpleLoader extends MultiFileLoader {
158
        public SimpleLoader() {
159
            super(SimpleObject.class.getName());
160
        }
161
        protected String displayName() {
162
            return "SimpleLoader";
163
        }
164
        @Override
165
        protected FileObject findPrimaryFile(FileObject fo) {
166
            if (fo.getNameExt().equals(TEMPLATE_NAME_EXT)) {
167
                return fo;
168
            }
169
            if (fo.getNameExt().equals(TESTFILE_NAME_EXT)) {
170
                return fo;
171
            }
172
            return null;
173
        }
174
        @Override
175
        protected MultiDataObject createMultiObject(FileObject primaryFile)
176
                                            throws DataObjectExistsException,
177
                                                   IOException {
178
            return new SimpleObject(this, primaryFile, isTestingFile(primaryFile));
179
        }
180
        @Override
181
        protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj,
182
                                                           FileObject primaryFile) {
183
            return new FE(obj, primaryFile);
184
        }
185
        @Override
186
        protected MultiDataObject.Entry createSecondaryEntry(MultiDataObject obj,
187
                                                             FileObject secondaryFile) {
188
            return new FE(obj, secondaryFile);
189
        }
190
        private static boolean isTestingFile(FileObject fileObj) {
191
            return fileObj.getNameExt().equals(TESTFILE_NAME_EXT);
192
        }
193
    }
194
195
    private static final class FE extends FileEntry {
196
        public FE(MultiDataObject mo, FileObject fo) {
197
            super(mo, fo);
198
        }
199
        @Override
200
        public FileObject createFromTemplate(FileObject f, String name) throws IOException {
201
            fail("FileEntry.createFromTemplate() should not be called");
202
            return null;
203
        }
204
    }
205
206
    public static final class SimpleObject extends MultiDataObject {
207
        private final Lookup lookup;
208
        public SimpleObject(SimpleLoader l,
209
                            FileObject fo,
210
                            boolean useSpecialEncoding)
211
                                              throws DataObjectExistsException {
212
            super(fo, l);
213
            lookup = useSpecialEncoding
214
                     ? Lookups.fixed(this, new TestEncoding())
215
                     : Lookups.singleton(this);
216
        }
217
        @Override
218
        public String getName() {
219
            return getPrimaryFile().getNameExt();
220
        }
221
        @Override
222
        public Lookup getLookup() {
223
            return lookup;
224
        }
225
    }
226
227
    public static final class TestEncoding extends FileEncodingQueryImplementation {
228
        @Override
229
        public Charset getEncoding(FileObject file) {
230
            return TEST_CHARSET;
231
        }
232
    }
233
234
    static final class TestCharset extends Charset {
235
        static int newDecoder;
236
        static int newEncoder;
237
238
        TestCharset() {
239
            super("test_charset", null);
240
        }
241
        @Override
242
        public boolean contains(Charset charset) {
243
            return true;
244
        }
245
        @Override
246
        public CharsetDecoder newDecoder() {
247
            newDecoder++;
248
            return Charset.forName("UTF-8").newDecoder();
249
        }
250
        @Override
251
        public CharsetEncoder newEncoder() {
252
            newEncoder++;
253
            return Charset.forName("UTF-8").newEncoder();
254
        }
255
    }
256
257
    public static final class Pool extends DataLoaderPool {
258
        @Override
259
        protected Enumeration<? extends DataLoader> loaders() {
260
            return Enumerations.singleton(SimpleLoader.getLoader(SimpleLoader.class));
261
        }
262
263
    }
264
}
(-)a/openide.loaders/test/unit/src/org/netbeans/modules/templates/IndentEngineIntTest.java (-227 lines)
Lines 1-227 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * Contributor(s):
28
 *
29
 * The Original Software is NetBeans. The Initial Developer of the Original
30
 * Software is Sun Microsystems, Inc.
31
 *
32
 * Portions Copyrighted 2007 Sun Microsystems, Inc.
33
 */
34
35
package org.netbeans.modules.templates;
36
37
import java.awt.Dialog;
38
import java.io.IOException;
39
import java.io.OutputStream;
40
import java.io.StringWriter;
41
import java.io.Writer;
42
import java.util.Collections;
43
import java.util.Enumeration;
44
import java.util.Map;
45
import javax.swing.text.Document;
46
import org.netbeans.junit.MockServices;
47
import org.netbeans.junit.NbTestCase;
48
import org.openide.DialogDescriptor;
49
import org.openide.DialogDisplayer;
50
import org.openide.NotifyDescriptor;
51
import org.openide.filesystems.FileObject;
52
import org.openide.filesystems.FileUtil;
53
import org.openide.loaders.DataFolder;
54
import org.openide.loaders.DataLoader;
55
import org.openide.loaders.DataLoaderPool;
56
import org.openide.loaders.DataObject;
57
import org.openide.loaders.DataObjectExistsException;
58
import org.openide.loaders.FileEntry;
59
import org.openide.loaders.MultiDataObject;
60
import org.openide.loaders.MultiFileLoader;
61
import org.openide.text.IndentEngine;
62
import org.openide.util.Enumerations;
63
64
/**
65
 *
66
 * @author Jaroslav Tulach
67
 */
68
public class IndentEngineIntTest extends NbTestCase {
69
    
70
    public IndentEngineIntTest(String testName) {
71
        super(testName);
72
    }
73
    
74
    protected boolean runInEQ() {
75
        return true;
76
    }
77
    
78
79
    @SuppressWarnings("deprecation")
80
    protected void setUp() throws Exception {
81
        MockServices.setServices(DD.class, Pool.class, IEImpl.class);
82
        FileUtil.setMIMEType("txt", "text/jarda");
83
    }
84
85
    protected void tearDown() throws Exception {
86
        super.tearDown();
87
    }
88
89
    public void testCreateFromTemplateUsingFreemarker() throws Exception {
90
        FileObject root = FileUtil.createMemoryFileSystem().getRoot();
91
        FileObject fo = FileUtil.createData(root, "simpleObject.txt");
92
        OutputStream os = fo.getOutputStream();
93
        String txt = "print('<html><h1>'); print(title); print('</h1></html>');";
94
        os.write(txt.getBytes());
95
        os.close();
96
        fo.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "JavaScript");
97
        
98
        
99
        DataObject obj = DataObject.find(fo);
100
        
101
        DataFolder folder = DataFolder.findFolder(FileUtil.createFolder(root, "target"));
102
        
103
        Map<String,String> parameters = Collections.singletonMap("title", "Nazdar");
104
        DataObject n = obj.createFromTemplate(folder, "complex", parameters);
105
        
106
        assertEquals("Created in right place", folder, n.getFolder());
107
        assertEquals("Created with right name", "complex.txt", n.getName());
108
        
109
        String exp = ">lmth/<>1h/<radzaN>1h<>lmth<";
110
        assertEquals(exp, stripNewLines(readFile(n.getPrimaryFile())));
111
        
112
    }
113
    
114
    static String stripNewLines(String str) {
115
        return str.replace("\n", "").replace("\r", "");
116
    }
117
    
118
    private static String readFile(FileObject fo) throws IOException {
119
        return fo.asText();
120
    }
121
    
122
    public static final class DD extends DialogDisplayer {
123
        public Object notify(NotifyDescriptor descriptor) {
124
            throw new UnsupportedOperationException("Not supported yet.");
125
        }
126
127
        public Dialog createDialog(final DialogDescriptor descriptor) {
128
            throw new UnsupportedOperationException("Not supported yet.");
129
        }
130
    }
131
    
132
    public static final class Pool extends DataLoaderPool {
133
        protected Enumeration<DataLoader> loaders() {
134
            return Enumerations.<DataLoader>singleton(SimpleLoader.getLoader(SimpleLoader.class));
135
        }
136
    }
137
    
138
    public static final class SimpleLoader extends MultiFileLoader {
139
        public SimpleLoader() {
140
            super(SimpleObject.class.getName());
141
        }
142
        protected String displayName() {
143
            return "SimpleLoader";
144
        }
145
        protected FileObject findPrimaryFile(FileObject fo) {
146
            if (fo.hasExt("prima")) {
147
                return fo;
148
            }
149
            return null;
150
        }
151
        protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException {
152
            return new SimpleObject(this, primaryFile);
153
        }
154
        protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj, FileObject primaryFile) {
155
            return new FE(obj, primaryFile);
156
        }
157
        protected MultiDataObject.Entry createSecondaryEntry(MultiDataObject obj, FileObject secondaryFile) {
158
            return new FileEntry(obj, secondaryFile);
159
        }
160
    }
161
    
162
    private static final class FE extends FileEntry {
163
        public FE(MultiDataObject mo, FileObject fo) {
164
            super(mo, fo);
165
        }
166
167
        @Override
168
        public FileObject createFromTemplate(FileObject f, String name) throws IOException {
169
            fail("I do not want to be called");
170
            return null;
171
        }
172
173
        
174
        
175
    }
176
    
177
    public static final class SimpleObject extends MultiDataObject {
178
        public SimpleObject(SimpleLoader l, FileObject fo) throws DataObjectExistsException {
179
            super(fo, l);
180
        }
181
        
182
        public String getName() {
183
            return getPrimaryFile().getNameExt();
184
        }
185
    }
186
187
    public static final class IEImpl extends IndentEngine {
188
        
189
        
190
        public int indentLine(Document doc, int offset) {
191
            throw new UnsupportedOperationException("Not supported yet.");
192
        }
193
194
        public int indentNewLine(Document doc, int offset) {
195
            throw new UnsupportedOperationException("Not supported yet.");
196
        }
197
198
        @Override
199
        protected boolean acceptMimeType(String mime) {
200
            return "text/jarda".equals(mime); // NOI18N
201
        }
202
203
        public Writer createWriter(Document doc, int offset, final Writer writer) {
204
            class Rotate extends StringWriter {
205
                @Override
206
                public void close() throws IOException {
207
                    super.close();
208
                    
209
                    String s = toString();
210
                    StringBuilder sb = new StringBuilder(s.length());
211
                    for (int i = s.length() - 1; i >= 0; i--) {
212
                        sb.append(s.charAt(i));
213
                    }
214
                    
215
                    writer.write(sb.toString());
216
                    writer.close();
217
                }
218
            }
219
            
220
            assertNotNull("There is some document", doc);
221
            assertEquals("Its length is 0", 0, doc.getLength());
222
            assertEquals("Offset is 0", 0, offset);
223
            
224
            return new Rotate();
225
        }
226
}
227
}
(-)a/openide.loaders/test/unit/src/org/netbeans/modules/templates/SCFTHandlerTest.java (-507 lines)
Lines 1-507 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * Contributor(s):
28
 *
29
 * The Original Software is NetBeans. The Initial Developer of the Original
30
 * Software is Sun Microsystems, Inc.
31
 *
32
 * Portions Copyrighted 2007 Sun Microsystems, Inc.
33
 */
34
35
package org.netbeans.modules.templates;
36
37
import java.awt.Dialog;
38
import java.io.BufferedReader;
39
import java.io.IOException;
40
import java.io.InputStream;
41
import java.io.InputStreamReader;
42
import java.io.OutputStream;
43
import java.io.OutputStreamWriter;
44
import java.nio.CharBuffer;
45
import java.nio.charset.Charset;
46
import java.util.Collections;
47
import java.util.Enumeration;
48
import java.util.HashMap;
49
import java.util.Iterator;
50
import java.util.Map;
51
import java.util.logging.Level;
52
import java.util.logging.Logger;
53
import org.netbeans.junit.MockServices;
54
import org.netbeans.junit.NbTestCase;
55
import org.netbeans.spi.queries.FileEncodingQueryImplementation;
56
import org.openide.DialogDescriptor;
57
import org.openide.DialogDisplayer;
58
import org.openide.NotifyDescriptor;
59
import org.openide.filesystems.FileObject;
60
import org.openide.filesystems.FileStateInvalidException;
61
import org.openide.filesystems.FileSystem;
62
import org.openide.filesystems.FileUtil;
63
import org.openide.filesystems.LocalFileSystem;
64
import org.openide.loaders.DataFolder;
65
import org.openide.loaders.DataLoader;
66
import org.openide.loaders.DataLoaderPool;
67
import org.openide.loaders.DataObject;
68
import org.openide.loaders.DataObjectExistsException;
69
import org.openide.loaders.FileEntry;
70
import org.openide.loaders.MultiDataObject;
71
import org.openide.loaders.MultiFileLoader;
72
import org.openide.util.Enumerations;
73
74
/**
75
 *
76
 * @author Jaroslav Tulach
77
 */
78
public class SCFTHandlerTest extends NbTestCase {
79
    static {
80
        // confuse the system a bit, if your system runs with UTF-8 default locale...
81
        //System.setProperty("file.encoding", "cp1252");
82
    }
83
    
84
    public SCFTHandlerTest(String testName) {
85
        super(testName);
86
    }
87
    
88
    @Override
89
    protected boolean runInEQ() {
90
        return true;
91
    }
92
93
    @Override
94
    protected Level logLevel() {
95
        return Level.FINE;
96
    }
97
    
98
    @Override
99
    protected void setUp() throws Exception {
100
        clearWorkDir();
101
        MockServices.setServices(DD.class, Pool.class, FEQI.class);
102
    }
103
104
    @Override
105
    protected void tearDown() throws Exception {
106
        super.tearDown();
107
    }
108
109
    public void testCreateFromTemplateUsingFreemarker() throws Exception {
110
        FileObject root = FileUtil.createMemoryFileSystem().getRoot();
111
        FileObject fo = FileUtil.createData(root, "simpleObject.txt");
112
        OutputStream os = fo.getOutputStream();
113
        String txt = "print('<html><h1>'); print(title); print('</h1></html>');";
114
        os.write(txt.getBytes());
115
        os.close();
116
        fo.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
117
        
118
        
119
        DataObject obj = DataObject.find(fo);
120
        
121
        DataFolder folder = DataFolder.findFolder(FileUtil.createFolder(root, "target"));
122
        
123
        Map<String,String> parameters = Collections.singletonMap("title", "Nazdar");
124
        DataObject n = obj.createFromTemplate(folder, "complex", parameters);
125
        
126
        assertEquals("Created in right place", folder, n.getFolder());
127
        assertEquals("Created with right name", "complex.txt", n.getName());
128
        
129
        String exp = "<html><h1>Nazdar</h1></html>";
130
        assertEquals(exp, readFile(n.getPrimaryFile()));
131
        
132
    }
133
134
    public void testCreateWithNameAndExt() throws Exception {
135
        FileObject root = FileUtil.createMemoryFileSystem().getRoot();
136
        FileObject fo = FileUtil.createData(root, "simpleObject.txt");
137
        OutputStream os = fo.getOutputStream();
138
        String txt = "print('<html><h1>'); print(nameAndExt); print('</h1></html>')";
139
        os.write(txt.getBytes());
140
        os.close();
141
        fo.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
142
        
143
        
144
        DataObject obj = DataObject.find(fo);
145
        
146
        DataFolder folder = DataFolder.findFolder(FileUtil.createFolder(root, "target"));
147
        
148
        Map<String,String> parameters = Collections.emptyMap();
149
        DataObject n = obj.createFromTemplate(folder, "complex", parameters);
150
        
151
        assertEquals("Created in right place", folder, n.getFolder());
152
        assertEquals("Created with right name", "complex.txt", n.getName());
153
        
154
        String exp = "<html><h1>complex.txt</h1></html>";
155
        assertEquals(exp, readFile(n.getPrimaryFile()));
156
        
157
    }
158
159
    public void testCreateWithNameAndExtForForm() throws Exception {
160
        LocalFileSystem lfs = new LocalFileSystem();
161
        lfs.setRootDirectory(getWorkDir());
162
        FileObject root = lfs.getRoot();
163
        FileObject fo = FileUtil.createData(root, "j.java");
164
        OutputStream os = fo.getOutputStream();
165
        String txt = "print('<html><h1>'); print(nameAndExt); print('</h1></html>')";
166
        os.write(txt.getBytes());
167
        os.close();
168
        fo.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
169
        
170
        FileObject fo2 = FileUtil.createData(root, "j.form");
171
        OutputStream os2 = fo2.getOutputStream();
172
        String txt2 = "print('<html><h2>'); print(nameAndExt); print('</h2></html>')";
173
        os2.write(txt2.getBytes());
174
        os2.close();
175
        fo2.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
176
        
177
        DataObject obj = DataObject.find(fo);
178
        assertEquals("Both files", 2, obj.files().size());
179
        
180
        DataFolder folder = DataFolder.findFolder(FileUtil.createFolder(root, "target"));
181
        
182
        Map<String,String> parameters = Collections.emptyMap();
183
        DataObject n = obj.createFromTemplate(folder, "complex", parameters);
184
        
185
        assertEquals("Two files", 2, n.files().size());
186
        
187
        
188
        FileObject newForm = FileUtil.findBrother(n.getPrimaryFile(), "form");
189
        
190
        assertEquals("Primary file is java", "java", n.getPrimaryFile().getExt());
191
        
192
        assertNotNull("Form copied", newForm);
193
        DataObject frm = DataObject.find(newForm);
194
        assertSame("Form belongs to java", n, frm);
195
        
196
        assertEquals("Created in right place", folder, n.getFolder());
197
        assertEquals("Created with right name", "complex", n.getName());
198
        
199
        String exp = "<html><h1>complex.java</h1></html>";
200
        assertEquals("Primary file" + n.getPrimaryFile(), exp, readFile(n.getPrimaryFile()));
201
        
202
        String exp2 = "<html><h2>complex.form</h2></html>";
203
        assertEquals(exp2, readFile(newForm));
204
    }
205
    
206
    public void testBasePropertiesAlwaysPresent() throws Exception {
207
        FileObject root = FileUtil.createMemoryFileSystem().getRoot();
208
        FileObject fo = FileUtil.createData(root, "simpleObject.txt");
209
        OutputStream os = fo.getOutputStream();
210
        String txt = "print('<html><h1>'); print(name); print('</h1>');" +
211
            "print('<h2>'); print(date); print('</h2>');" +
212
            "print('<h3>'); print(time); print('</h3>');" +
213
            "print('<h4>'); print(user); print('</h4>');" +
214
            "print('<h4>'); print(dateTime.getTime()); print('</h4>');" +
215
            "print('</html>');";
216
        os.write(txt.getBytes());
217
        os.close();
218
        fo.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
219
        
220
        
221
        DataObject obj = DataObject.find(fo);
222
        
223
        DataFolder folder = DataFolder.findFolder(FileUtil.createFolder(root, "target"));
224
        
225
        Map<String,String> parameters = Collections.singletonMap("title", "Nazdar");
226
        DataObject n = obj.createFromTemplate(folder, "complex", parameters);
227
        
228
        assertEquals("Created in right place", folder, n.getFolder());
229
        assertEquals("Created with right name", "complex.txt", n.getName());
230
        
231
        String res = readFile(n.getPrimaryFile());
232
        
233
        if (res.indexOf("date") >= 0) fail(res);
234
        if (res.indexOf("time") >= 0) fail(res);
235
        if (res.indexOf("user") >= 0) fail(res);
236
        if (res.indexOf("name") >= 0) fail(res);
237
        if (res.indexOf("dateTime") >= 0) fail(res);
238
    }
239
    
240
    private static String readFile(FileObject fo) throws IOException {
241
        byte[] arr = new byte[(int)fo.getSize()];
242
        int len = fo.getInputStream().read(arr);
243
        assertEquals("Fully read", arr.length, len);
244
        return new String(arr);
245
    }
246
247
    private static String readChars(FileObject fo, Charset set) throws IOException {
248
        CharBuffer arr = CharBuffer.allocate((int)fo.getSize() * 2);
249
        BufferedReader r = new BufferedReader(new InputStreamReader(fo.getInputStream(), set));
250
        while (r.read(arr) != -1) {
251
            // again
252
        }
253
        r.close();
254
        
255
        arr.flip();
256
        return arr.toString();
257
    }
258
259
     public void testUTF8() throws Exception {
260
         FileObject root = FileUtil.getConfigRoot();
261
         FileObject xmldir = FileUtil.createFolder(root, "xml");
262
         FileObject xml = FileUtil.createData(xmldir, "class.txt");
263
         OutputStream os = xml.getOutputStream();
264
         FileUtil.copy(getClass().getResourceAsStream("utf8.xml"), os);
265
         xml.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
266
         os.close();
267
         
268
         DataObject obj = DataObject.find(xml);
269
         
270
         
271
         FileObject target = FileUtil.createFolder(FileUtil.createMemoryFileSystem().getRoot(), "dir");
272
         DataFolder folder = DataFolder.findFolder(FileUtil.createFolder(target, "target"));
273
         
274
         
275
         
276
         Charset set = Charset.forName("iso-8859-2");
277
         FEQI.fs = target.getFileSystem();
278
         FEQI.result = set;
279
         
280
         
281
         Map<String,String> parameters = Collections.singletonMap("title", "Nazdar");
282
         DataObject n = obj.createFromTemplate(folder, "complex", parameters);
283
         
284
         assertEquals("Created in right place", folder, n.getFolder());
285
         assertEquals("Created with right name", "complex.txt", n.getName());
286
         
287
         
288
         String read = readChars(n.getPrimaryFile(), set).replaceAll("println\\('", "").replaceAll("'\\);", "");
289
         String exp = readChars(xml, Charset.forName("utf-8")).replaceAll("println\\('", "").replaceAll("'\\);", "");
290
         assertEquals(exp, read);
291
         
292
     }
293
294
    public void testTemplateWizardCopiesItsPropertiesToMapForOverridenEntryOnMoreEntries() throws Exception {
295
        LocalFileSystem fs = new LocalFileSystem();
296
        fs.setRootDirectory(getWorkDir());
297
        
298
        FileObject root = fs.getRoot();
299
        FileObject fo = FileUtil.createData(root, "simpleObject.java");
300
        FileObject fo2 = FileUtil.createData(root, "simpleObject.form");
301
        fo.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
302
        fo2.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
303
304
        Charset set = Charset.forName("iso-8859-2");
305
        OutputStream os = fo2.getOutputStream();
306
        OutputStreamWriter w = new OutputStreamWriter(os, set);
307
        String txt = "print('skvělej tým, co nikdy neusíná - ěščřžýáíéúů')";
308
        w.write(txt);
309
        w.close();
310
        
311
        
312
        DataObject obj = DataObject.find(fo);
313
        assertEquals(TwoPartObject.class, obj.getClass());
314
        TwoPartObject tpo = (TwoPartObject)obj;
315
        tpo.encoding = set;
316
        
317
        FileObject root2 = FileUtil.createMemoryFileSystem().getRoot();
318
        DataFolder folder = DataFolder.findFolder(FileUtil.createFolder(root2, "target"));
319
        
320
        Map<String,String> parameters = Collections.singletonMap("type", "empty");
321
        
322
        FEQI.fs = root2.getFileSystem();
323
        FEQI.result = Charset.forName("UTF-8");
324
        
325
        DataObject n = obj.createFromTemplate(folder, "complex", parameters);
326
        Integer cnt = TwoPartLoader.queried.get(n.getPrimaryFile());
327
        assertEquals("No query", null, cnt);
328
        
329
        assertEquals("Created in right place", folder, n.getFolder());
330
        assertEquals("Created with right name", "complex", n.getName());
331
        Iterator<FileObject> it = n.files().iterator();
332
        it.next();
333
        FileObject snd = it.next();
334
        
335
        long length = snd.getSize();
336
        if (length <= 0) {
337
            fail("Too small file: " + length + " for " + snd);
338
        }
339
        InputStream is = snd.getInputStream();
340
        InputStreamReader r = new InputStreamReader(is, "UTF-8");
341
        char[] cbuf = new char[1024];
342
        int len = r.read(cbuf);
343
        if (len == -1) {
344
            fail("no input stream for " + snd);
345
        }
346
        String read = new String(cbuf, 0, len);
347
        txt = txt.replaceAll("print\\('", "").replaceAll("'\\)", "");
348
        
349
        assertEquals(txt, read);
350
    }
351
     
352
    public static final class DD extends DialogDisplayer {
353
        public Object notify(NotifyDescriptor descriptor) {
354
            throw new UnsupportedOperationException("Not supported yet.");
355
        }
356
357
        public Dialog createDialog(final DialogDescriptor descriptor) {
358
            throw new UnsupportedOperationException("Not supported yet.");
359
            /*
360
            return new JDialog() {
361
                @Deprecated
362
                public void show() {
363
                    for (Object object : descriptor.getOptions()) {
364
                        if (object instanceof JButton) {
365
                            JButton b = (JButton)object;
366
                            if (b.getText().equals("Finish")) {
367
                                descriptor.setValue(WizardDescriptor.FINISH_OPTION);
368
                                b.doClick();
369
                                return;
370
                            }
371
                        }
372
                    }
373
                    fail("Cannot find Finish button: " + Arrays.asList(descriptor.getOptions()));
374
                }
375
            };
376
             */
377
        }
378
    }
379
380
    public static final class FEQI extends FileEncodingQueryImplementation {
381
        public static FileSystem fs;
382
        public static Charset result;
383
    
384
        public Charset getEncoding(FileObject f) {
385
            try {
386
                if (f.getFileSystem() == fs) {
387
                    return result;
388
                }
389
                return null;
390
            } catch (FileStateInvalidException ex) {
391
                return null;
392
            }
393
        }
394
    }
395
    
396
    public static final class Pool extends DataLoaderPool {
397
        protected Enumeration<DataLoader> loaders() {
398
            return Enumerations.<DataLoader>array(new DataLoader[] { 
399
                TwoPartLoader.getLoader(TwoPartLoader.class),
400
                SimpleLoader.getLoader(SimpleLoader.class),
401
            });
402
        }
403
    }
404
    
405
    public static final class SimpleLoader extends MultiFileLoader {
406
        public SimpleLoader() {
407
            super(SimpleObject.class.getName());
408
        }
409
        protected String displayName() {
410
            return "SimpleLoader";
411
        }
412
        protected FileObject findPrimaryFile(FileObject fo) {
413
            if (fo.hasExt("prima")) {
414
                return fo;
415
            }
416
            return null;
417
        }
418
        protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException {
419
            return new SimpleObject(this, primaryFile);
420
        }
421
        protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj, FileObject primaryFile) {
422
            return new FE(obj, primaryFile);
423
        }
424
        protected MultiDataObject.Entry createSecondaryEntry(MultiDataObject obj, FileObject secondaryFile) {
425
            return new FileEntry(obj, secondaryFile);
426
        }
427
    }
428
    
429
    private static final class FE extends FileEntry {
430
        public FE(MultiDataObject mo, FileObject fo) {
431
            super(mo, fo);
432
        }
433
434
        @Override
435
        public FileObject createFromTemplate(FileObject f, String name) throws IOException {
436
            fail("I do not want to be called");
437
            return null;
438
        }
439
440
        
441
        
442
    }
443
    
444
    public static final class SimpleObject extends MultiDataObject {
445
        public SimpleObject(SimpleLoader l, FileObject fo) throws DataObjectExistsException {
446
            super(fo, l);
447
        }
448
        
449
        @Override
450
        public String getName() {
451
            return getPrimaryFile().getNameExt();
452
        }
453
    }
454
455
    static final Logger LOG = Logger.getLogger("tst.TwoPartLoader");
456
    public static final class TwoPartLoader extends MultiFileLoader {
457
        static Map<FileObject,Integer> queried = new HashMap<FileObject,Integer>();
458
        
459
        public TwoPartLoader() {
460
            super(TwoPartObject.class.getName ());
461
        }
462
        protected String displayName() {
463
            return "TwoPart";
464
        }
465
        protected FileObject findPrimaryFile(FileObject fo) {
466
            Integer i = queried.get(fo);
467
            queried.put(fo, i == null ? 1 : i + 1);
468
            FileObject ret;
469
            
470
            if (fo.hasExt("java") || fo.hasExt("form")) {
471
                ret = org.openide.filesystems.FileUtil.findBrother(fo, "java");
472
            } else {
473
                ret = null;
474
            }
475
            
476
            LOG.fine("findPrimaryFile for " + fo + " yeilded " + ret);
477
            return ret;
478
        }
479
        protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException {
480
            LOG.info("New data object for " + primaryFile);
481
            return new TwoPartObject(this, primaryFile);
482
        }
483
        protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj, FileObject primaryFile) {
484
            LOG.fine("new primary entry " + primaryFile);
485
            return new FE(obj, primaryFile);
486
        }
487
        protected MultiDataObject.Entry createSecondaryEntry(MultiDataObject obj, FileObject secondaryFile) {
488
            LOG.fine("new snd entry: " + secondaryFile);
489
            return new FE(obj, secondaryFile);
490
        }
491
    }
492
    public static final class TwoPartObject extends MultiDataObject {
493
        public TwoPartObject(TwoPartLoader l, FileObject folder) throws DataObjectExistsException {
494
            super(folder, l);
495
            getCookieSet().assign(FileEncodingQueryImplementation.class, eq);
496
        }
497
        private Charset encoding;
498
        private FileEncodingQueryImplementation eq = new FileEncodingQueryImplementation() {
499
500
            public Charset getEncoding(FileObject file) {
501
                return encoding;
502
            }
503
            
504
        };
505
    }
506
    
507
}
(-)a/openide.loaders/test/unit/src/org/netbeans/modules/templates/ScriptingCreateFromTemplateTest.java (-235 lines)
Lines 1-235 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * Contributor(s):
28
 *
29
 * The Original Software is NetBeans. The Initial Developer of the Original
30
 * Software is Sun Microsystems, Inc.
31
 *
32
 * Portions Copyrighted 2007 Sun Microsystems, Inc.
33
 */
34
35
package org.netbeans.modules.templates;
36
37
import java.io.IOException;
38
import java.io.OutputStream;
39
import java.nio.charset.Charset;
40
import java.util.Collections;
41
import java.util.HashMap;
42
import java.util.Map;
43
import javax.script.ScriptEngine;
44
import javax.swing.text.DefaultEditorKit;
45
import javax.swing.text.Document;
46
import org.netbeans.api.editor.mimelookup.MimePath;
47
import org.netbeans.api.queries.FileEncodingQuery;
48
import org.netbeans.junit.MockServices;
49
import org.netbeans.junit.NbTestCase;
50
import org.openide.filesystems.FileObject;
51
import org.openide.filesystems.FileUtil;
52
import org.openide.loaders.DataFolder;
53
import org.openide.loaders.DataObject;
54
import org.openide.loaders.DataObjectExistsException;
55
import org.openide.loaders.FileEntry;
56
import org.openide.loaders.MultiDataObject;
57
import org.openide.loaders.MultiFileLoader;
58
import org.netbeans.api.editor.mimelookup.test.MockMimeLookup;
59
import org.openide.loaders.CreateFromTemplateHandler;
60
import org.openide.util.SharedClassObject;
61
import org.openide.util.test.MockLookup;
62
63
/**
64
 *
65
 * @author Marek Fukala
66
 * @author Jaroslav Tulach
67
 */
68
public class ScriptingCreateFromTemplateTest extends NbTestCase {
69
    
70
    public ScriptingCreateFromTemplateTest(String testName) {
71
        super(testName);
72
    }
73
    
74
    @Override
75
    protected boolean runInEQ() {
76
        return true;
77
    }
78
    
79
    @Override
80
    protected void setUp() throws Exception {
81
        MockLookup.setInstances(SharedClassObject.findObject(SimpleLoader.class, true));
82
    }
83
84
    public void testCreateFromTemplateEncodingProperty() throws Exception {
85
        FileObject root = FileUtil.createMemoryFileSystem().getRoot();
86
        FileObject fo = FileUtil.createData(root, "simpleObject.txt");
87
        OutputStream os = fo.getOutputStream();
88
        os.write("print(encoding)".getBytes());
89
        os.close();
90
        assertEquals("content/unknown", fo.getMIMEType());
91
        fo.setAttribute ("template", Boolean.TRUE);
92
        assertEquals("content/unknown", fo.getMIMEType());
93
        fo.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
94
        
95
        DataObject obj = DataObject.find(fo);
96
        DataFolder folder = DataFolder.findFolder(FileUtil.createFolder(root, "target"));
97
        
98
        Map<String,String> parameters = Collections.emptyMap();
99
        DataObject inst = obj.createFromTemplate(folder, "complex", parameters);
100
        FileObject instFO = inst.getPrimaryFile();
101
        
102
        Charset targetEnc = FileEncodingQuery.getEncoding(instFO);
103
        assertNotNull("Template encoding is null", targetEnc);
104
        String instText = IndentEngineIntTest.stripNewLines(instFO.asText());
105
        assertEquals("Encoding in template doesn't match", targetEnc.name(), instText);
106
    }
107
108
    public void testFreeFileExtension() throws Exception {
109
        FileObject root = FileUtil.createMemoryFileSystem().getRoot();
110
        FileObject template = FileUtil.createData(root, "simple.pl");
111
        OutputStream os = template.getOutputStream();
112
        ScriptEngine jsEngine = new javax.script.ScriptEngineManager().getEngineByExtension("js");
113
        boolean isNashorn = (jsEngine != null && jsEngine.toString().indexOf("Nashorn") > 0);
114
        if (isNashorn) {
115
            // print() behaves like println() and println() does not exist:
116
            os.write("print('#!/usr/bin/perl'); print('# '+license); print('# '+name+' in '+nameAndExt);".getBytes());
117
        } else {
118
            os.write("println('#!/usr/bin/perl'); print('# ');println(license);print('# ');print(name);print(' in ');println(nameAndExt);".getBytes());
119
        }
120
        os.close();
121
        template.setAttribute("template", true);
122
        template.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
123
        Map<String,Object> parameters = new HashMap<String,Object>();
124
        parameters.put("license", "GPL");
125
        parameters.put(CreateFromTemplateHandler.FREE_FILE_EXTENSION, true);
126
        String newLine = isNashorn ? System.getProperty("line.separator") : "\n";
127
            FileObject inst = DataObject.find(template).createFromTemplate(DataFolder.findFolder(root), "nue", parameters).getPrimaryFile();
128
            assertEquals("#!/usr/bin/perl"+newLine+"# GPL"+newLine+"# nue in nue.pl"+newLine, inst.asText());
129
            assertEquals("nue.pl", inst.getPath());
130
            /* XXX perhaps irrelevant since typical wizards disable Finish in this condition
131
            inst = DataObject.find(template).createFromTemplate(DataFolder.findFolder(root), "nue", parameters).getPrimaryFile();
132
            assertEquals("#!/usr/bin/perl\n# GPL\n# nue_1 in nue_1.pl\n", inst.asText());
133
            assertEquals("nue_1.pl", inst.getPath());
134
             */
135
            inst = DataObject.find(template).createFromTemplate(DataFolder.findFolder(root), "nue.cgi", parameters).getPrimaryFile();
136
            assertEquals("#!/usr/bin/perl"+newLine+"# GPL"+newLine+"# nue in nue.cgi"+newLine, inst.asText());
137
            assertEquals("nue.cgi", inst.getPath());
138
            /* XXX
139
            inst = DataObject.find(template).createFromTemplate(DataFolder.findFolder(root), "nue.cgi", parameters).getPrimaryFile();
140
            assertEquals("#!/usr/bin/perl\n# GPL\n# nue_1 in nue_1.cgi\n", inst.asText());
141
            assertEquals("nue_1.cgi", inst.getPath());
142
             */
143
            inst = DataObject.find(template).createFromTemplate(DataFolder.findFolder(root), "explicit.pl", parameters).getPrimaryFile();
144
            assertEquals("#!/usr/bin/perl"+newLine+"# GPL"+newLine+"# explicit in explicit.pl"+newLine, inst.asText());
145
            assertEquals("explicit.pl", inst.getPath());
146
            /* XXX
147
            inst = DataObject.find(template).createFromTemplate(DataFolder.findFolder(root), "explicit.pl", parameters).getPrimaryFile();
148
            assertEquals("#!/usr/bin/perl\n# GPL\n# explicit_1 in explicit_1.pl\n", inst.asText());
149
            assertEquals("explicit_1.pl", inst.getPath());
150
             */
151
    }
152
    
153
    //fix for this test was rolled back because of issue #120865
154
    public void XtestCreateFromTemplateDocumentCreated() throws Exception {
155
        FileObject root = FileUtil.createMemoryFileSystem().getRoot();
156
        FileObject fo = FileUtil.createData(root, "simpleObject.txt");
157
        OutputStream os = fo.getOutputStream();
158
        os.write("test".getBytes());
159
        os.close();
160
        fo.setAttribute ("template", Boolean.TRUE);
161
        fo.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
162
163
        MockServices.setServices(MockMimeLookup.class);
164
        MockMimeLookup.setInstances(MimePath.parse("content/unknown"), new TestEditorKit());
165
        
166
        DataObject obj = DataObject.find(fo);
167
        DataFolder folder = DataFolder.findFolder(FileUtil.createFolder(root, "target"));
168
        
169
        assertFalse(TestEditorKit.createDefaultDocumentCalled);
170
        DataObject inst = obj.createFromTemplate(folder, "test");
171
        assertTrue(TestEditorKit.createDefaultDocumentCalled);
172
        
173
        String exp = "test";
174
        assertEquals(exp, inst.getPrimaryFile().asText());
175
    }
176
    
177
    public static final class SimpleLoader extends MultiFileLoader {
178
        public SimpleLoader() {
179
            super(SimpleObject.class.getName());
180
        }
181
        protected String displayName() {
182
            return "SimpleLoader";
183
        }
184
        protected FileObject findPrimaryFile(FileObject fo) {
185
            if (fo.hasExt("prima")) {
186
                return fo;
187
            }
188
            return null;
189
        }
190
        protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException {
191
            return new SimpleObject(this, primaryFile);
192
        }
193
        protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj, FileObject primaryFile) {
194
            return new FE(obj, primaryFile);
195
        }
196
        protected MultiDataObject.Entry createSecondaryEntry(MultiDataObject obj, FileObject secondaryFile) {
197
            return new FileEntry(obj, secondaryFile);
198
        }
199
    }
200
    
201
    private static final class FE extends FileEntry {
202
        public FE(MultiDataObject mo, FileObject fo) {
203
            super(mo, fo);
204
        }
205
206
        @Override
207
        public FileObject createFromTemplate(FileObject f, String name) throws IOException {
208
            fail("I do not want to be called");
209
            return null;
210
        }
211
    }
212
    
213
    public static final class SimpleObject extends MultiDataObject {
214
        public SimpleObject(SimpleLoader l, FileObject fo) throws DataObjectExistsException {
215
            super(fo, l);
216
        }
217
        
218
        public String getName() {
219
            return getPrimaryFile().getNameExt();
220
        }
221
    }
222
    
223
    private static final class TestEditorKit extends DefaultEditorKit {
224
        
225
        static boolean createDefaultDocumentCalled;
226
227
        @Override
228
        public Document createDefaultDocument() {
229
            createDefaultDocumentCalled = true;
230
            return super.createDefaultDocument();
231
        }
232
        
233
    }
234
235
}
(-)a/openide.loaders/test/unit/src/org/netbeans/modules/templates/utf8.xml (-4 lines)
Lines 1-4 Link Here
1
println('<?xml version="1.0"?>');
2
println('<root>');
3
println('    Žluťoučký kůň skákal přes čtvero mezí.');
4
println('</root>');
(-)a/openide.loaders/test/unit/src/org/openide/loaders/CreateFromTemplateHandlerTest.java (-2 / +2 lines)
Lines 205-216 Link Here
205
        public static String name;
205
        public static String name;
206
        public static Map<String, Object> parameters;
206
        public static Map<String, Object> parameters;
207
    
207
    
208
        protected boolean accept(FileObject fo) {
208
        public boolean accept(FileObject fo) {
209
            acceptObject.add(fo);
209
            acceptObject.add(fo);
210
            return true;
210
            return true;
211
        }
211
        }
212
212
213
        protected FileObject createFromTemplate(
213
        public FileObject createFromTemplate(
214
            FileObject orig, FileObject f, String n,
214
            FileObject orig, FileObject f, String n,
215
            Map<String, Object> p
215
            Map<String, Object> p
216
        ) throws IOException {
216
        ) throws IOException {

Return to bug 247926