+ API allows to create new files based on templates. Scripting engines can be specified for
+ processing the template, or custom Handlers may be registered to process certain templates.
+
+
+ A template can use places substituable with parameter values; certain well-known parameters are
+ predefined, if the caller does not provide its custom values.
+
+
+
+
+ The feature will be fully covered by unit tests.
+
+
+
+
+ October 2014
+
+
+
+
+
+
+
+
+
+ An existing file can be used as a boilerplate for creation of a new file.
+ The boiler plate can contain necessary skeleton, comments, content. As the
+ boilerplate resides on config filesystem, it is also customizable by the user
+ and the user can eventually develop custom templates.
+
+
+ In previous NetBeans versions, templating system was built into
+ .
+
+
+
+
+ Often many people require ability to create a "clever" template - e.g.
+ write piece of simple text and at the time of its
+
+ processing
+
+ do some advanced changes to it using either
+ scripting or templating languages.
+
+
+ This traditionally used to be a bit complicated task (hacking into DataObject implementation), however since
+ version 6.1 there are interface in
+
+ DataSystem API
+
+ and finally
+
+ that can be registered as a services in a lookup and it is reponsible
+ for handling the whole copy of the template file(s) to the destination
+ folder.
+
+
+
+
+
+ Runtime or project-related values may be supplied by
+
+ that can be registered as a services in a lookup and it is reponsible
+ for providing "hints" - e.g. map mapping strings to various objects.
+ and these interfaces allow anyone to extend the behaviour during
+ creation of new files.
+
+
+ The CreateFromTemplateAttribute implementation
+ knows which template is being used, where the outcome should be placed, so it can derive appropriate values for both
+ the template and the target location.
+
+
+
+
+ There is a built in support for scripting languages in
+ the standard NetBeans IDE. If a template is annotated with
+
+ a property that can be associated to templates that either should
+ return real instance of ScriptEngine interface or
+ a String name of the engine that is then used to
+ search for it in the javax.script.ScriptEngineManager.
+ Usually the freemarker engine is the one that is
+ supported by the NetBeans IDE - if your module wants to use it
+ then include a token dependency OpenIDE-Module-Needs: javax.script.ScriptEngine.freemarker
+ in your manifest file (also accessible through project customizer GUI)
+ to indicate to the system that you need it.
+
+ then the scripting engine is then used to process the template and
+ generate the output file. While running the engine one can rely
+ on few predefined properties:
+
+
+
+
contains the name of the DataObject that is being created
+
contains the name the user
+
contains the name and extension of the file that is being created
+
contains String representing the current day like 23. 3. 2007
+
contains String the current time like 17:18:30
+
contains java.util.Date representing current data and time like
+
contains String the file encoding of the template instance
+
+
+
+ Other properties can indeed be provided by
+ CreateFromTemplateAttributess.
+ After processing, the output is also sent to appropriate
+ org.openide.text.IndentEngine associated
+ with the mime type of the template, for formating.
+
+
+
+ Smart Templating Quick How-To
+
+
+ First of all create a file in your module layer located somewhere
+ under the Templates/ folder. Make it a template by
+ adding <attr name="template" boolvalue="true"/>. Associate
+ this template with a scripting language, for example by
+ <attr name="javax.script.ScriptEngine" stringvalue="freemarker"/>.
+ Now make sure that the scripting language integration is also available
+ by requesting a token in standard format, for freemarker just put
+ OpenIDE-Module-Needs: javax.script.ScriptEngine.freemarker
+ in your manifest. This tells the NetBeans module system that a
+ module providing integration with such scripting engine has to be
+ enabled. Now you can use regular script language tags inside of
+ your template file. When you write your instantiate
+ method in your wizard, you can create a Map<String,Object> and
+ fill it with parameters collected from your wizard and then pass it
+ to
+
+ createFromTemplate(targetFolder, targetName, mapWithParameters)
+ . This will invoke the scripting language and make the
+ mapWithParameters values available to it. Beyond this
+ there is few standard parameters predefined including name, user, date, time, etc.
+ and also additional parameters are collected from all registered
+ CreateFromTemplateAttributesProviders.
+
+
+
+
+
+ A CreateFromTemplateHandler
+ should be able to create multiple files, one of them important so it will open after user
+ initiates the creation action. The template of set of related files may be represented by a folder with
+ a handler attached, and the operation deploys multiple files in the target directory.
+
+
+
+
+
+ This utility standardizes the process to use files as blueprints to create new files.
+
+
+
+
+
+
+
+ This module replaces some implementation in DataSystem APIs so the implementation
+ is usable even without DataSystems API itself. DataSystems API will use this
+ library.
+
+
+
+
+ Yes.
+
+
+
+
+ No.
+
+
+
+
+ Yes.
+
+
+
+
+ Requires JRE 7, for implementation reasons (AutoCloseable).
+
+
+
+
+ JRE
+
+
+
+
+
+
+
+ None.
+
+
+
+
+ No native platform dependencies.
+
+
+
+
+ No specific deploy dependencies.
+
+
+
+
+ JARs only.
+
+
+
+
+ Yes.
+
+
+
+
+ Yes, except API.
+
+
+
+
+ Anywhere.
+
+
+
+
+ No.
+
+
+
+
+ No.
+
+
+
+
+ No.
+
+
+
+
+ No.
+
+
+
+
+ No.
+
+
+
+
+ No.
+
+
+
+
+
+ A special ScriptEngine type is required to perform indentation on the produced sources.
+ The ScriptEngine must provide a name "org.netbeans.api.templates.IndentEngine".
+ The only attribute property passed to the ScriptContext is mimeType of the
+ text being formatted.
+
+
+
+
+ A parameter for template creation, possibly specified as a template file layer attribute that controls
+ how the extension for the new file is computed. See
+ CreateDescriptor javadoc for the details.
+
+
+
+
+ A parameter for template creation, possibly specified as a template file layer attribute that controls
+ formatting of the produced text. See
+ CreateDescriptor javadoc for the details.
+
+
+ Registers handler, which integrates scripting engines using javax.script API. Provides an annotation
+ processor, so it is easy to register - see
+ TemplateRegistration annotation.
+
+
+
+
+ No.
+
+
+
+
+ No.
+
+
+
+
+ No UI.
+
+
+
+
+ Files are processed in-memory in documents; practical limits are imposed
+ by the platform's Document implementation.
+
+
+
+
+ See 'perf-limit'
+
+
+
+
+ No UI.
+
+
+
+
+ No.
+
+
+
+
+ XXX no answer for perf-scale
+
+
+
+
+ No practical enforcement.
+
+
+
+
+ No.
+
+
+
+
+ No.
+
+
+
+
+ No.
+
+
+
+
+ No.
+
+
+
+
+ No.
+
+
+
+
+ No.
+
+
+
+
+ No.
+
+
+
+
+ No.
+
+
+
+
+ No.
+
+
+
+
diff --git a/api.templates/build.xml b/api.templates/build.xml
new file mode 100644
--- /dev/null
+++ b/api.templates/build.xml
@@ -0,0 +1,5 @@
+
+
+ Builds, tests, and runs the project org.netbeans.api.templates
+
+
diff --git a/api.templates/manifest.mf b/api.templates/manifest.mf
new file mode 100644
--- /dev/null
+++ b/api.templates/manifest.mf
@@ -0,0 +1,6 @@
+Manifest-Version: 1.0
+AutoUpdate-Show-In-Client: false
+OpenIDE-Module: org.netbeans.api.templates
+OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/templates/Bundle.properties
+OpenIDE-Module-Specification-Version: 1.0
+OpenIDE-Module-Recommends: org.netbeans.templates.IndentEngine
diff --git a/api.templates/nbproject/project.properties b/api.templates/nbproject/project.properties
new file mode 100644
--- /dev/null
+++ b/api.templates/nbproject/project.properties
@@ -0,0 +1,3 @@
+javac.source=1.7
+javac.compilerargs=-Xlint -Xlint:-serial
+javadoc.arch=${basedir}/arch.xml
diff --git a/api.templates/nbproject/project.xml b/api.templates/nbproject/project.xml
new file mode 100644
--- /dev/null
+++ b/api.templates/nbproject/project.xml
@@ -0,0 +1,129 @@
+
+
+ org.netbeans.modules.apisupport.project
+
+
+ org.netbeans.api.templates
+
+
+ org.netbeans.api.annotations.common
+
+
+
+ 1
+ 1.25
+
+
+
+ org.netbeans.modules.nbjunit
+
+
+
+ 1
+ 1.85
+
+
+
+ org.netbeans.modules.queries
+
+
+
+ 1
+ 1.40
+
+
+
+ org.openide.filesystems
+
+
+
+ 9.1
+
+
+
+ org.openide.util
+
+
+
+ 9.3
+
+
+
+ org.openide.util.lookup
+
+
+
+ 8.26
+
+
+
+
+
+ unit
+
+ org.netbeans.libs.freemarker
+
+
+ org.netbeans.modules.editor.mimelookup
+
+
+
+
+ org.netbeans.modules.editor.mimelookup.impl
+
+
+ org.netbeans.modules.masterfs
+
+
+ org.openide.awt
+
+
+ org.openide.dialogs
+
+
+
+ org.openide.loaders
+
+
+
+ org.openide.nodes
+
+
+
+ org.openide.util.lookup
+
+
+
+
+ org.openide.modules
+
+
+ org.netbeans.modules.masterfs
+
+
+ org.netbeans.modules.editor.document
+
+
+
+
+ org.netbeans.modules.editor.indent
+
+
+
+
+ org.openide.util.ui
+
+
+
+ org.netbeans.modules.editor.lib
+
+
+
+
+
+ org.netbeans.api.templates
+ org.openide.loaders
+
+
+
+
diff --git a/api.templates/src/org/netbeans/api/templates/CreateDescriptor.java b/api.templates/src/org/netbeans/api/templates/CreateDescriptor.java
new file mode 100644
--- /dev/null
+++ b/api.templates/src/org/netbeans/api/templates/CreateDescriptor.java
@@ -0,0 +1,208 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2014 Sun Microsystems, Inc.
+ */
+package org.netbeans.api.templates;
+
+import java.util.Collections;
+import java.util.Locale;
+import java.util.Map;
+import org.netbeans.api.annotations.common.CheckForNull;
+import org.netbeans.api.annotations.common.NonNull;
+import org.openide.filesystems.FileObject;
+
+/**
+ * Describes file creation request. The description is produced by the
+ * {@link FileBuilder} and is sent out to
+ * {@link CreateFromTemplateAttribute} and {@link CreateFromTemplateHandler}
+ * SPIs as the context for their work.
+ *
+ * The class is not thread-safe. Do not access the descriptor from a thread other
+ * than executing the {@link CreateFromTemplateHandler} callbacks.
+ *
+ * @author sdedic
+ */
+public final class CreateDescriptor {
+ /**
+ * Parameter to enable free file extension mode.
+ * By default, the extension of the newly created file will be inherited
+ * from the template. But if {@link #createFromTemplate} is called with this
+ * parameter set to {@link Boolean#TRUE}
+ * (such as from {@link DataObject#createFromTemplate(DataFolder,String,Map)}),
+ * and the file name already seems to
+ * include an extension (*.*), the handler should not append
+ * any extension from the template.
+ * @since org.openide.loaders 7.16
+ * @see Templates.SimpleTargetChooserBuilder.freeFileExtension
+ */
+ public static final String FREE_FILE_EXTENSION = "freeFileExtension"; // NOI18N
+
+ /**
+ * Specifies that no formatting or indentation should be performed on the template.
+ * The parameter can be specified as parameter to the template (possibly through layer registration
+ * of the template. Value is kept for backwards compatibility, but the attribute does not apply
+ * just to java templates.
+ *
+ * It's responsibility of {@link CreateFromTemplateHandler} to pay attention to this value.
+ */
+ public static final String PREFORMATTED_TEMPLATE = "org-netbeans-modules-java-preformattedSource"; // NOI18N
+
+
+ private final FileObject template;
+ private final FileObject target;
+
+ /**
+ * The originally specified name for the new file
+ */
+ @SuppressWarnings("PackageVisibleField")
+ String name;
+
+ /**
+ * The proposed name - either specified, or computed
+ */
+ @SuppressWarnings("PackageVisibleField")
+ String proposedName;
+
+ /**
+ * Template parameters
+ */
+ @SuppressWarnings("PackageVisibleField")
+ Map parameters;
+
+ /**
+ * The locale used for file creation
+ */
+ Locale locale = Locale.getDefault();
+
+ /**
+ * The extension is supplied as a part of the name
+ */
+ boolean freeExtension;
+
+ /**
+ * If true, the template is preformatted and no indentation should
+ * take place.
+ */
+ boolean preformatted;
+
+ /* package private */
+ CreateDescriptor(FileObject template, FileObject target) {
+ this.template = template;
+ this.target = target;
+ }
+
+ /**
+ * @return the template file
+ */
+ public @NonNull FileObject getTemplate() {
+ return template;
+ }
+
+ /**
+ * @return the target folder
+ */
+ public @NonNull FileObject getTarget() {
+ return target;
+ }
+
+ /**
+ * Provides the desired name for the created file. {@code null} can be
+ * returned to indicate the filename should be derived automatically.
+ * @return name for the created file
+ */
+ public @CheckForNull String getName() {
+ return name;
+ }
+
+ /**
+ * Provides a name proposed for the file. If the caller specified the name,
+ * the value will be the same as {@link #getName}. A handler is encouraged
+ * to use the proposed name if it does not require a certain naming scheme.
+ * @return proposed name for the created file
+ */
+ public @NonNull String getProposedName() {
+ return proposedName != null ? proposedName : name;
+ }
+
+ /**
+ * Provides the desired user locale for creating the template
+ * @return locale
+ */
+ public @NonNull Locale getLocale() {
+ return locale;
+ }
+
+ /**
+ * Provides value for the named key. Values are originally provided by
+ * the caller, or the template itself; values can be provided also by
+ * {@link CreateFromTemplateAttribute} implementors.
+ *
+ * @param value type.
+ * @param n key name
+ * @return named value or {@code null} if the key does not exist/has no value.
+ */
+ @CheckForNull
+ public T getValue(String n) {
+ return (T)parameters.get(n);
+ }
+
+ /**
+ * Provides access to the complete parameter map.
+ * @return readonly string-value map.
+ */
+ public @NonNull Map getParameters() {
+ return parameters == null ? Collections.emptyMap() :
+ Collections.unmodifiableMap(parameters);
+ }
+
+ /**
+ * Specifies whether the extension should be taken from the specified name,
+ * or the extension is fixed to the template's one.
+ *
+ * @return true, if the name contains already the extension.
+ */
+ public boolean hasFreeExtension() {
+ return freeExtension;
+ }
+
+ public boolean isPreformatted() {
+ return preformatted;
+ }
+}
diff --git a/api.templates/src/org/netbeans/api/templates/CreateFromTemplateAttributes.java b/api.templates/src/org/netbeans/api/templates/CreateFromTemplateAttributes.java
new file mode 100644
--- /dev/null
+++ b/api.templates/src/org/netbeans/api/templates/CreateFromTemplateAttributes.java
@@ -0,0 +1,67 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc.
+ *
+ * Portions Copyrighted 2007 Sun Microsystems, Inc.
+ */
+
+package org.netbeans.api.templates;
+
+import java.util.Map;
+
+/** This is an interface for smart templating.
+ * Implementations of this class can be registered in the global {@link org.openide.util.Lookup}
+ * and allows anyone provide additional parameters to each {@link CreateFromTemplateHandler}s
+ * when a template is instantiating.
+ *
+ * Implementations are called in the order of appearance in Lookup. The positions less than 0 are
+ * reserved for the platform. Implementations called later can see and override
+ * values defined by earlier CreateFromTemplateAttributes.
+ *
+ * Read more in the howto document.
+ *
+ * This interface supersedes {@code CreateFromTemplateAttributesProvider} in {@code openide.loaders} module.
+ *
+ * @author Svata Dedic
+ */
+public interface CreateFromTemplateAttributes {
+ /** Called when a template is about to be instantiated to provide additional
+ * values to the {@link CreateFromTemplateHandler} that will handle the
+ * template instantiation.
+ *
+ * If the returned Map defines the same value as some {@link CreateFromTemplateAttributes} registered
+ * earlier, the Map's value takes precedence. Parameters supplied by the {@link FileBuilder} cannot be
+ * overriden.
+ *
+ * @param desc the creation request
+ * @return map of named objects, or null
+ */
+ Map attributesFor(CreateDescriptor desc);
+}
diff --git a/api.templates/src/org/netbeans/api/templates/CreateFromTemplateHandler.java b/api.templates/src/org/netbeans/api/templates/CreateFromTemplateHandler.java
new file mode 100644
--- /dev/null
+++ b/api.templates/src/org/netbeans/api/templates/CreateFromTemplateHandler.java
@@ -0,0 +1,77 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc.
+ *
+ * Portions Copyrighted 2007 Sun Microsystems, Inc.
+ */
+
+package org.netbeans.api.templates;
+
+import java.io.IOException;
+import java.util.List;
+import org.netbeans.api.annotations.common.NonNull;
+import org.openide.filesystems.FileObject;
+
+/** This is an interface for smart templating that allows
+ * any module to intercept calls to
+ * DataObject.createFromTemplate()
+ * and handle them themselves. The NetBeans IDE provides default
+ * implementation that allows use of Freemarker templating engine.
+ * Read more in the howto document.
+ *
+ * An implementation of CreateHandler should honor {@link CreateDescriptor#hasFreeExtension()} and
+ * {@link CreateDescriptor#isPreformatted()}.
+ *
+ * @author Jaroslav Tulach
+ * @author Svatopluk Dedic
+ */
+public abstract class CreateFromTemplateHandler {
+ /** Method that allows a handler to reject a file. If all handlers
+ * reject a file, regular processing defined in {@link DataObject#handleCreateFromTemplate}
+ * is going to take place.
+ *
+ * @param desc
+ * @return true if this handler wants to handle the createFromTemplate operation
+ */
+ protected abstract boolean accept(CreateDescriptor desc);
+
+ /** Handles the creation of new files. The Handler may create one or more files. The
+ * files should be ordered so that the "important" file (i.e. the one which is then presented
+ * to the user etc) is ordered first in the list.
+ *
+ * @param desc command objects that describes the file creation request
+ * @return the newly create file
+ * @throws IOException if something goes wrong with I/O
+ */
+ protected abstract @NonNull List createFromTemplate(
+ CreateDescriptor desc
+ ) throws IOException;
+
+}
diff --git a/api.templates/src/org/netbeans/api/templates/CreateFromTemplateImpl.java b/api.templates/src/org/netbeans/api/templates/CreateFromTemplateImpl.java
new file mode 100644
--- /dev/null
+++ b/api.templates/src/org/netbeans/api/templates/CreateFromTemplateImpl.java
@@ -0,0 +1,309 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2014 Sun Microsystems, Inc.
+ */
+package org.netbeans.api.templates;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.text.Format;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptException;
+import org.netbeans.api.queries.FileEncodingQuery;
+import org.netbeans.modules.templates.ScriptingCreateFromTemplateHandler;
+import org.openide.filesystems.FileLock;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.util.Lookup;
+import org.openide.util.MapFormat;
+import org.openide.util.Parameters;
+
+/**
+ *
+ * @author sdedic
+ */
+final class CreateFromTemplateImpl {
+ private static final String PROP_TEMPLATE = "template"; // NOI18N
+ private static final String NEWLINE = "\n"; // NOI18N
+
+ private final FileBuilder builder;
+ private final CreateDescriptor desc;
+ private Map originalParams;
+
+ private CreateFromTemplateImpl(FileBuilder builder) {
+ this.builder = builder;
+ this.desc = builder.getDescriptor();
+ }
+
+ static List build(FileBuilder flb) throws IOException {
+ CreateFromTemplateImpl impl = new CreateFromTemplateImpl(flb);
+ return impl.build();
+ }
+
+ List build() throws IOException {
+ // side effects: replaces the map in CreateDescriptor
+ try {
+ FileObject f = desc.getTemplate();
+ FileObject folder = desc.getTarget();
+ FileBuilder.Mode defaultMode = null;
+ Format frm = null;
+ Parameters.notNull("f", f);
+ Parameters.notNull("folder", folder);
+ assert defaultMode != FileBuilder.Mode.FORMAT || frm != null : "Format must be provided for Mode.FORMAT";
+
+ if (!folder.isFolder()) {
+ throw new IllegalArgumentException("Not a folder: " + folder);
+ }
+ // also modifies desc.getParameters, result not needed.
+ findTemplateParameters();
+ computeEffectiveName();
+
+ List pf = null;
+ for (CreateFromTemplateHandler h : Lookup.getDefault().lookupAll(CreateFromTemplateHandler.class)) {
+ if (h.accept(desc)) {
+ pf = h.createFromTemplate(desc);
+ assert pf != null && !pf.isEmpty();
+ break;
+ }
+ }
+ if (pf != null) {
+ return pf;
+ }
+ // side effects from findTemplateParameters still in effect...
+ return Collections.singletonList(defaultCreate());
+ } finally {
+ // bring back the parameters
+ builder.getDescriptor().parameters = (Map)originalParams;
+ }
+ }
+
+ private void computeEffectiveName() {
+ String name = desc.getName();
+ if (name == null) {
+ // name is not set - try to check parameters, if some template attribute handler
+ // did not supply a suggestion:
+ Object o = desc.getParameters().get("name");
+ if (o instanceof String) {
+ name = (String)o;
+ } else {
+ name = FileUtil.findFreeFileName(
+ desc.getTarget(), desc.getTemplate().getName (), desc.getTemplate().getExt ()
+ );
+ }
+ }
+ desc.proposedName = name;
+ }
+
+ /**
+ * Populates default values for template parameters. Each template can have its specific parameters and their default values
+ * are defined by {@link CreateFromTemplateAttributes} SPI registered in the Lookup. The 'param' provides user-defined values,
+ * which always take precedence over the defaults.
+ *
+ * Certain values are always filled in, if not specified:
+ *
+ *
{@code user} the invoking user name
+ *
{@code date} system date : String
+ *
{@code time} system time : String
+ *
{@code dateTime} java.util.Date representation of the current system time
+ *
+ *
+ * @param template
+ * @param folder
+ * @param name
+ * @param param
+ * @return completed parameters
+ */
+ public Map findTemplateParameters() {
+ // IMPORTANT: all map is exposed through CreateDescriptor !
+ HashMap all = new HashMap();
+ all.putAll(desc.getParameters());
+ originalParams = desc.parameters;
+ desc.parameters = all;
+ for (CreateFromTemplateAttributes provider : Lookup.getDefault().lookupAll(CreateFromTemplateAttributes.class)) {
+ Map map = provider.attributesFor(desc);
+ if (map != null) {
+ for (Map.Entry e : map.entrySet()) {
+ // allow each CFTA override previous CFTAs, but not user-provided params
+ if (originalParams == null || !originalParams.containsKey(e.getKey())) {
+ all.put(e.getKey(), e.getValue());
+ }
+ }
+ }
+ }
+ String name = desc.getName();
+ if (!all.containsKey("name") && name != null) { // NOI18N
+ String n = name;
+ if (desc.hasFreeExtension()) {
+ n = name.replaceFirst("[.].*", "");
+ }
+ all.put("name", n); // NOI18N
+ //desc.name = name;
+ }
+ Date d = new Date();
+ if (!all.containsKey("dateTime")) { // NOI18N
+ all.put("dateTime", d); // NOI18N
+ }
+ String ext = desc.getTemplate().getExt();
+ if (!all.containsKey("nameAndExt") && name != null) { // NOI18N
+ if (ext != null && ext.length() > 0 && originalParams != null &&
+ (!desc.hasFreeExtension() || name.indexOf('.') == -1)) {
+ all.put("nameAndExt", name + '.' + ext); // NOI18N
+ } else {
+ all.put("nameAndExt", name); // NOI18N
+ }
+ }
+ return all;
+ }
+
+ /**
+ * Creates the file using the default algorithm - no handler is willing to participate
+ * @return created file
+ * @throws IOException
+ */
+ private FileObject defaultCreate() throws IOException {
+// if (pf != null || defaultMode == TemplateUtils.Mode.FAIL) {
+// return pf;
+// }
+ Map params = desc.getParameters();
+ FileBuilder.Mode defaultMode = builder.defaultMode;
+ Format frm = builder.format;
+
+ if (defaultMode != FileBuilder.Mode.COPY && frm instanceof MapFormat) {
+ MapFormat mf = (MapFormat)frm;
+ Map m = mf.getMap();
+ for (String s: params.keySet()) {
+ if (m.containsKey(s)) {
+ continue;
+ }
+ m.put(s, params.get(s));
+ }
+ }
+ FileObject f = desc.getTemplate();
+ String ext = desc.getTemplate().getExt();
+ FileObject fo = desc.getTarget().createData (desc.getProposedName(), ext);
+ boolean preformatted = false;
+ Charset encoding = FileEncodingQuery.getEncoding(f);
+ boolean success = false;
+ FileLock lock = fo.lock ();
+ try (InputStream is= f.getInputStream ();
+ Reader reader = new InputStreamReader(is,encoding);
+ BufferedReader r = new BufferedReader (reader)) {
+
+ preformatted = desc.isPreformatted();
+ encoding = FileEncodingQuery.getEncoding(fo);
+
+ //Document doc = ScriptingCreateFromTemplateHandler.createDocument(f.getMIMEType());
+ ScriptEngine en = desc.isPreformatted() ? null : ScriptingCreateFromTemplateHandler.indentEngine();
+ // PENDING: originally, preformatted meant that only changed
+ // lines were formatted. Now preformatted is not formatted at all
+ StringWriter sw = new StringWriter();
+ try (
+ OutputStream os=fo.getOutputStream(lock);
+ OutputStreamWriter w = new OutputStreamWriter(os, encoding);
+ Writer iw = preformatted || en == null ? w : sw) {
+
+ String line = null;
+ String current;
+
+ while ((current = r.readLine ()) != null) {
+ if (line != null) {
+ // newline between lines
+ iw.append(NEWLINE);
+ }
+ if (frm != null) {
+ line = frm.format (current);
+ } else {
+ line = current;
+ }
+ iw.append(line);
+ }
+ iw.append(NEWLINE);
+ iw.flush();
+
+ if (en != null) {
+ en.getContext().setAttribute("mimeType", f.getMIMEType(), ScriptContext.ENGINE_SCOPE);
+ en.getContext().setWriter(w);
+ en.eval(new StringReader(sw.toString()));
+ }
+ }
+ // copy attributes
+ // hack to overcome package-private modifier in setTemplate(fo, boolean)
+ FileUtil.copyAttributes(f, fo);
+ fo.setAttribute(PROP_TEMPLATE, null);
+ success = true;
+ } catch (IOException ex) {
+ try {
+ fo.delete(lock);
+ } catch (IOException ex2) {
+ }
+ throw ex;
+ } catch (ScriptException ex) {
+ IOException io = ex.getCause() instanceof IOException ? (IOException)ex.getCause() : null;
+ try {
+ fo.delete(lock);
+ } catch (IOException ex2) {
+ }
+ throw io == null ? new IOException(ex) : io;
+ } finally {
+ if (!success) {
+ // try to delete the malformed file:
+ fo.delete(lock);
+ }
+ lock.releaseLock();
+ }
+ return fo;
+ }
+
+}
diff --git a/api.templates/src/org/netbeans/api/templates/FileBuilder.java b/api.templates/src/org/netbeans/api/templates/FileBuilder.java
new file mode 100644
--- /dev/null
+++ b/api.templates/src/org/netbeans/api/templates/FileBuilder.java
@@ -0,0 +1,310 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2014 Sun Microsystems, Inc.
+ */
+package org.netbeans.api.templates;
+
+import java.io.IOException;
+import java.text.FieldPosition;
+import java.text.Format;
+import java.text.ParsePosition;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import org.netbeans.api.annotations.common.CheckForNull;
+import org.netbeans.api.annotations.common.NonNull;
+import org.netbeans.api.annotations.common.NullAllowed;
+import org.openide.filesystems.FileObject;
+import org.openide.util.MapFormat;
+
+/**
+ * Fluent interface for file creation. The Builder is first parametrized. After
+ * everything is set up, call {@link #build} to materialize the template using
+ * the supplied parameters/settings.
+ *
+ * The create file(s) get names derived from the template and the existing target folder
+ * contents (so that the filenames do not conflict with existing files). A desired
+ * filename can be set up by {@link #name}.
+ *
+ * The file build request will be forwarded to {@link CreateFromTemplateHandler}s; if none
+ * {@link CreateFromTemplateHandler#accept}s the request, the default procedure takes place,
+ * depending on the {@link #defaultMode} setting (default: {@link Mode#COPY}).
+ *
+ * There are several values predefined:
+ *
name - the created filename without extension
+ *
nameAndExt - the created filename including the extension
+ *
date - date of creation, printed in the default date format
+ *
dateTime - {@link Date} object representing the creation time
+ *
time - time of creation, printed in the default time format
+ *
user - the user id of the user creating the file
+ *
+ *
+ * @author sdedic
+ */
+public final class FileBuilder {
+ /**
+ * Determines the default procedure for copying the template in {@link #createFromTemplate}.
+ */
+ public static enum Mode {
+ /**
+ * The template will be formatted using formatter.
+ */
+ FORMAT,
+ /**
+ * The template will be just copied.
+ */
+ COPY,
+ /**
+ * The template will not be processed if no custom {@link CreateFromTemplateHandler} handles it.
+ */
+ FAIL
+ }
+
+ /**
+ * Creates a new FileBuilder for a specific template and target folder.
+ * @param template the template to use.
+ * @param target the target folder; must already exist.
+ */
+ public FileBuilder(@NonNull FileObject template, @NonNull FileObject target) {
+ descriptor = new CreateDescriptor(template, target);
+ }
+
+ /**
+ * Specifies the locale to be used during file creation.
+ * The locale also applies to the standard parameters passed to the template (e.g. date and time representation).
+ * @param l the locale
+ * @return this FileBuilder instance.
+ */
+ public FileBuilder useLocale(@NonNull Locale l) {
+ descriptor.locale = l;
+ return this;
+ }
+
+ /**
+ * Sets the desired target file's name.
+ *
+ * @param n the name
+ * @return this FileBuilder instance
+ */
+ public FileBuilder name(String n) {
+ descriptor.name = n;
+ return this;
+ }
+
+ /**
+ * Includes parameters for the template.
+ * For backwards compatibility, special parameters {@link CreateDescriptor#FREE_FILE_EXTENSION} and
+ * {@link CreateDescriptor#PREFORMATTED_TEMPLATE} are processed and appropriate properties modified on the
+ * CreateDescriptor.
+ *
+ * @param params the string-value pairs
+ * @return this FileBuilder instance
+ */
+ public FileBuilder withParameters(@NullAllowed Map params) {
+ if (descriptor.parameters != null) {
+ descriptor.parameters.putAll(params);
+ } else {
+ descriptor.parameters = params == null ? null : new HashMap<>(params);
+ }
+ if (params != null) {
+ Object v = params.get(CreateDescriptor.FREE_FILE_EXTENSION);
+ if (v instanceof Boolean) {
+ boolean val = Boolean.TRUE.equals(v);
+ descriptor.freeExtension = val;
+ }
+ v = params.get(CreateDescriptor.PREFORMATTED_TEMPLATE);
+ if (v instanceof Boolean) {
+ boolean val = Boolean.TRUE.equals(v);
+ descriptor.preformatted = val;
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Adds a parameter to the template.
+ * For backwards compatibility, special parameters {@link CreateDescriptor#FREE_FILE_EXTENSION} and
+ * {@link CreateDescriptor#PREFORMATTED_TEMPLATE} are processed and appropriate properties modified on the
+ * CreateDescriptor.
+ *
+ * @param n parameter name
+ * @param v the value
+ * @return this FileBuilder instance
+ */
+ public FileBuilder param(@NonNull String n, Object v) {
+ if (descriptor.parameters == null) {
+ descriptor.parameters = new HashMap<>();
+ }
+ descriptor.parameters.put(n, v);
+ if (v instanceof Boolean) {
+ if (CreateDescriptor.FREE_FILE_EXTENSION.equals(n)) {
+ boolean val = Boolean.TRUE.equals(v);
+ descriptor.freeExtension = val;
+ }
+ if (CreateDescriptor.PREFORMATTED_TEMPLATE.equals(n)) {
+ boolean val = Boolean.TRUE.equals(v);
+ descriptor.preformatted = val;
+ }
+ }
+ return this;
+ }
+
+ /**
+ * Specifies the behaviour to be used when no {@link CreateFromTemplateHandler} accepts the template.
+ * @param m the default processing mode
+ * @return this FileBuilder instance
+ * @see Mode for details
+ */
+ public FileBuilder defaultMode(@NonNull Mode m) {
+ this.defaultMode = m;
+ return this;
+ }
+
+ /**
+ * Uses the specified formatter for file creation. Also sets the default mode to
+ * {@link Mode#FORMAT}. If the supplied Format instance happens to be a
+ * {@link MapFormat}, the templating code will pass parameters produced by
+ * {@link CreateFromTemplateAttributes} to the format when the target file
+ * contents is generated.
+ *
+ * @param def the format to use
+ * @return this FileBuilder instance
+ * @see Mode for details on different modes
+ */
+ public FileBuilder useFormat(@NonNull Format def) {
+ this.format = def;
+ return defaultMode(Mode.FORMAT);
+ }
+
+ /**
+ * Creates the file(s) from template.
+ * @return list of created files. If some file is 'master' or otherwise of high importance and represents
+ * the file set, it should be placed first in the list.
+ * @throws IOException if the creation fails
+ */
+ public @CheckForNull List build() throws IOException {
+ return CreateFromTemplateImpl.build(this);
+ }
+
+ CreateDescriptor getDescriptor() {
+ return descriptor;
+ }
+
+ private final CreateDescriptor descriptor;
+
+ @SuppressWarnings("PackageVisibleField")
+ Mode defaultMode;
+
+ @SuppressWarnings("PackageVisibleField")
+ Format format;
+
+
+ /**
+ * Creates a new file based on the template. This convenience method is intended for easier
+ * migration of clients using DataLoader templating API before {@link FileBuilder} introduction.
+ * The method will collect parameters
+ * tied to the template using registered {@link CreateFromTemplateAttributes} providers,
+ * and will try to locate a willing {@link CreateFromTemplateHandler} that will create
+ * the target file. If no such handler exists, and the {@code defaultCopy} parameter is true,
+ * the file contents is just copied to the target location.
+ *
+ * If the {@code name} parameter is null, the function attempts to compute a suitable name
+ * from the file.
+ *
+ * The default copy algorithm uses the supplied {@code format} to process tokens. A standard
+ * format (using __TOKEN__) can be obtained by calling {@link #basicFormatter}.
+ *
+ * If the passed {@code name} is {@code null}, the implementation will pick a free name based on
+ * the template's own name (see {@link FileUtil#findFreeFileName}).
+ * @param f the template file
+ * @param folder the target folder, must exist
+ * @param name the desired name. If {@code null}, the implementation will choose the name.
+ * @param attributes values to apply on the template. May be {@code null} = no values.
+ * @return The created file, or {@code null} if no creation handler is located.
+ * @throws IOException
+ */
+ @SuppressWarnings("AssignmentToMethodParameter")
+ @CheckForNull
+ public static FileObject createFromTemplate(@NonNull FileObject f, @NonNull FileObject folder,
+ @NullAllowed String name, @NullAllowed Map attributes,
+ Mode defaultMode)
+ throws IOException {
+ Format frm = null;
+
+ switch (defaultMode) {
+ case FORMAT:
+ MapFormat mf = new MapFormat(new HashMap());
+ mf.setExactMatch(false);
+ mf.setLeftBrace("__");
+ mf.setRightBrace("__");
+ frm = mf;
+ break;
+
+ case COPY:
+ frm = new Format() {
+ @Override
+ public StringBuffer format(Object obj, StringBuffer toAppendTo, FieldPosition pos) {
+ toAppendTo.append(obj);
+ return toAppendTo;
+ }
+
+ @Override
+ public Object parseObject(String source, ParsePosition pos) {
+ throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
+ }
+ };
+ break;
+ }
+ FileBuilder fb = new FileBuilder(f, folder).
+ name(name).
+ withParameters(attributes).
+ useFormat(frm).
+ defaultMode(defaultMode);
+
+ List fos = fb.build();
+ if (fos == null || fos.isEmpty()) {
+ return null;
+ } else {
+ return fos.iterator().next();
+ }
+ }
+}
diff --git a/api.templates/src/org/netbeans/api/templates/TemplateRegistration.java b/api.templates/src/org/netbeans/api/templates/TemplateRegistration.java
new file mode 100644
--- /dev/null
+++ b/api.templates/src/org/netbeans/api/templates/TemplateRegistration.java
@@ -0,0 +1,140 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development and
+ * Distribution License("CDDL") (collectively, the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy of
+ * the License at http://www.netbeans.org/cddl-gplv2.html or
+ * nbbuild/licenses/CDDL-GPL-2-CP. See the License for the specific language
+ * governing permissions and limitations under the License. When distributing
+ * the software, include this License Header Notice in each file and include
+ * the License file at nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided by
+ * Oracle in the GPL Version 2 section of the License file that accompanied
+ * this code. If applicable, add the following below the License Header, with
+ * the fields enclosed by brackets [] replaced by your own identifying
+ * information: "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you do not indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to its
+ * licensees as provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the option applies only
+ * if the new code is made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2011 Sun Microsystems, Inc.
+ */
+
+package org.netbeans.api.templates;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import javax.script.ScriptEngineFactory;
+
+/**
+ * Registers a template the user can select.
+ * May be placed on a class (with a default constructor) or static method (with no arguments)
+ * to register an {@link InstantiatingIterator} for a custom template;
+ * or on a package to register a plain-file template with no custom behavior.
+ * @since 7.29
+ * @see TemplateWizard
+ * @see TemplateRegistrations
+ * @see org.netbeans.spi.project.ui.templates.support
+ */
+@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PACKAGE})
+@Retention(RetentionPolicy.SOURCE)
+public @interface TemplateRegistration {
+
+ /**
+ * Subfolder in which to place the template, such as {@code Other} or {@code Project/Standard}.
+ */
+ String folder();
+
+ /**
+ * Optional position within {@link #folder}.
+ */
+ int position() default Integer.MAX_VALUE;
+
+ /**
+ * Special file basename to use rather than inferring one from the declaring element,
+ * when {@link #content} is empty.
+ * Useful for pure templates referenced from {@code PrivilegedTemplates}.
+ */
+ String id() default "";
+
+ /**
+ * File contents, as resources relative to the package of this declaration.
+ * A nonempty list is mandatory for a template registered on a package.
+ * For a template with a custom iterator, the content may be omitted, though it may still be specified.
+ *
Normally only a single file is specified, but for a multifile data object, list the primary entry first.
+ *
The file basenames (incl. extension) of the actual template files (as in {@link TemplateWizard#getTemplate})
+ * will be taken from the basename of the content resources, though a {@code .template} suffix
+ * may be appended to prevent template resources in a source project from being misinterpreted.
+ * For a "pure" custom iterator with no specified content, the template basename
+ * defaults to the FQN of the class or method defining it but with {@code -} for {@code .} characters,
+ * e.g. {@code pkg-Class-method}, but may be overridden with {@link #id}.
+ *
Example usage for a simple, single-file template (with or without custom iterator):
+ *
+ */
+ String[] content() default {};
+
+ /**
+ * Localized label for the template.
+ * Mandatory unless {@link #content} is specified, in which case it would be defaulted by the data node.
+ * May use the usual {@code #key} syntax.
+ */
+ String displayName() default "";
+
+ /**
+ * Icon to use for the template.
+ * Should be an absolute resource path (no initial slash).
+ * Mandatory unless {@link #content} is specified, in which case it would be defaulted by the data node.
+ */
+ String iconBase() default "";
+
+ /**
+ * Optional but recommended relative resource path to an HTML description of the template.
+ * @see TemplateWizard#getDescription
+ */
+ String description() default "";
+
+ /**
+ * Optional name of a script engine to use when processing file content, such as {@code freemarker}.
+ * @see ScriptEngineFactory#getNames
+ */
+ String scriptEngine() default "";
+
+ /**
+ * Optional list of categories interpreted by the project system.
+ */
+ String[] category() default {};
+
+ /**
+ * Set to false if the template can be instantiated without a project.
+ * @since 7.46
+ */
+ boolean requireProject() default true;
+
+ /**
+ * Default (pre-filled) target name for the template, without extension. May
+ * use the usual {@code #key} syntax for localization or branding.
+ *
+ * @since 7.56
+ */
+ String targetName() default "";
+}
diff --git a/api.templates/src/org/netbeans/api/templates/TemplateRegistrations.java b/api.templates/src/org/netbeans/api/templates/TemplateRegistrations.java
new file mode 100644
--- /dev/null
+++ b/api.templates/src/org/netbeans/api/templates/TemplateRegistrations.java
@@ -0,0 +1,56 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development and
+ * Distribution License("CDDL") (collectively, the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy of
+ * the License at http://www.netbeans.org/cddl-gplv2.html or
+ * nbbuild/licenses/CDDL-GPL-2-CP. See the License for the specific language
+ * governing permissions and limitations under the License. When distributing
+ * the software, include this License Header Notice in each file and include
+ * the License file at nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided by
+ * Oracle in the GPL Version 2 section of the License file that accompanied
+ * this code. If applicable, add the following below the License Header, with
+ * the fields enclosed by brackets [] replaced by your own identifying
+ * information: "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you do not indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to its
+ * licensees as provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the option applies only
+ * if the new code is made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2011 Sun Microsystems, Inc.
+ */
+
+package org.netbeans.api.templates;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * May be used to register multiple plain-file {@link TemplateRegistration}s.
+ * Use on a package for simple templates, or on an iterator for multiple variants of a template
+ * with different {@link TemplateRegistration#content}.
+ * @since 7.29
+ */
+@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PACKAGE})
+@Retention(RetentionPolicy.SOURCE)
+public @interface TemplateRegistrations {
+ TemplateRegistration[] value();
+}
diff --git a/api.templates/src/org/netbeans/modules/templates/Bundle.properties b/api.templates/src/org/netbeans/modules/templates/Bundle.properties
new file mode 100644
--- /dev/null
+++ b/api.templates/src/org/netbeans/modules/templates/Bundle.properties
@@ -0,0 +1,7 @@
+OpenIDE-Module-Display-Category=Infrastructure
+OpenIDE-Module-Long-Description=\
+ Provides API to create files based on templates. Supports scripting in templates \
+ and allows to plug in code that handles file creation, or supplies project or \
+ environment data for template creation.
+OpenIDE-Module-Name=File Templates
+OpenIDE-Module-Short-Description=Supports file creation based on templates
diff --git a/api.templates/src/org/netbeans/modules/templates/ScriptingCreateFromTemplateHandler.java b/api.templates/src/org/netbeans/modules/templates/ScriptingCreateFromTemplateHandler.java
new file mode 100644
--- /dev/null
+++ b/api.templates/src/org/netbeans/modules/templates/ScriptingCreateFromTemplateHandler.java
@@ -0,0 +1,180 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc.
+ *
+ * Portions Copyrighted 2007 Sun Microsystems, Inc.
+ */
+
+package org.netbeans.modules.templates;
+
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.nio.charset.Charset;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import javax.script.Bindings;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+import org.netbeans.api.queries.FileEncodingQuery;
+import org.netbeans.api.templates.CreateDescriptor;
+import org.netbeans.api.templates.CreateFromTemplateHandler;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.util.Lookup;
+import org.openide.util.lookup.ServiceProvider;
+
+
+/** Processes templates that have associated attribute
+* with name of the scripting engine.
+*
+* @author Jaroslav Tulach
+*/
+@ServiceProvider(service=CreateFromTemplateHandler.class)
+public class ScriptingCreateFromTemplateHandler extends CreateFromTemplateHandler {
+
+ public static final String SCRIPT_ENGINE_ATTR = "javax.script.ScriptEngine";
+
+ private static ScriptEngineManager manager;
+
+ private static final String ENCODING_PROPERTY_NAME = "encoding"; //NOI18N
+
+ @Override
+ public boolean accept(CreateDescriptor desc) {
+ return engine(desc.getTemplate()) != null;
+ }
+
+ @Override
+ public List createFromTemplate(CreateDescriptor desc) throws IOException {
+ FileObject template = desc.getTemplate();
+ String name = desc.getProposedName();
+ Map values = desc.getParameters();
+ FileObject f = desc.getTarget();
+
+ boolean noExt = desc.hasFreeExtension() && name.indexOf('.') != -1;
+
+ String extWithDot;
+ if (noExt) {
+ extWithDot = null;
+ } else {
+ extWithDot = '.' + template.getExt();
+ if (name.endsWith(extWithDot)) { // Test whether the extension happens to be there already
+ // And remove it if yes, it will be appended to the unique name.
+ name = name.substring(0, name.length() - extWithDot.length());
+ }
+ }
+
+ String nameUniq = FileUtil.findFreeFileName(f, name, noExt ? null : template.getExt());
+ FileObject output = FileUtil.createData(f, noExt ? nameUniq : nameUniq + extWithDot);
+ Charset targetEnc = FileEncodingQuery.getEncoding(output);
+ Charset sourceEnc = FileEncodingQuery.getEncoding(template);
+
+ ScriptEngine eng = engine(template);
+ Bindings bind = eng.getContext().getBindings(ScriptContext.ENGINE_SCOPE);
+ bind.putAll(values);
+
+ if(!values.containsKey(ENCODING_PROPERTY_NAME)) {
+ bind.put(ENCODING_PROPERTY_NAME, targetEnc.name());
+ }
+
+ //Document doc = createDocument(template.getMIMEType());
+ try (Writer w = new OutputStreamWriter(output.getOutputStream(), targetEnc);
+ Reader is = new InputStreamReader(template.getInputStream(), sourceEnc);
+ /*IndentWriter w2 = new IndentWriter(doc, 0, w, false) */) {
+ StringWriter sw = new StringWriter();
+ ScriptEngine eng2 = desc.isPreformatted() ? null : indentEngine();
+
+ eng.getContext().setWriter(new PrintWriter(eng2 != null ? sw : w));
+ //eng.getContext().setBindings(bind, ScriptContext.ENGINE_SCOPE);
+ eng.getContext().setAttribute(FileObject.class.getName(), template, ScriptContext.ENGINE_SCOPE);
+ eng.getContext().setAttribute(ScriptEngine.FILENAME, template.getNameExt(), ScriptContext.ENGINE_SCOPE);
+ eng.eval(is);
+
+ if (eng2 != null) {
+ eng2.getContext().setAttribute("mimeType", template.getMIMEType(), ScriptContext.ENGINE_SCOPE);
+ eng2.getContext().setWriter(w);
+ eng2.eval(new StringReader(sw.toString()));
+ }
+ }catch (ScriptException ex) {
+ IOException io = new IOException(ex.getMessage(), ex);
+ throw io;
+ }
+ return Collections.singletonList(output);
+ }
+
+ public static ScriptEngine indentEngine() {
+ return getEngine(ID_INDENT_ENGINE);
+ }
+
+ private static final String ID_INDENT_ENGINE = "org.netbeans.api.templates.IndentEngine"; // NOI18N
+
+ public static ScriptEngine getEngine(String engName) {
+ synchronized (ScriptingCreateFromTemplateHandler.class) {
+ if (manager == null) {
+ ClassLoader loader = Lookup.getDefault().lookup(ClassLoader.class);
+ manager = new ScriptEngineManager(loader != null ? loader : Thread.currentThread().getContextClassLoader());
+ }
+ }
+ return manager.getEngineByName(engName);
+ }
+
+ private static ScriptEngine engine(FileObject fo) {
+ Object obj = fo.getAttribute(SCRIPT_ENGINE_ATTR); // NOI18N
+ if (obj instanceof ScriptEngine) {
+ return (ScriptEngine)obj;
+ }
+ if (obj instanceof String) {
+ return getEngine((String)obj);
+ }
+ return null;
+ }
+
+ /*
+ public static Document createDocument(String mimeType) {
+ Document doc;
+ try {
+ doc = LineDocumentUtils.createDocument(mimeType);
+ } catch (IllegalArgumentException ex) {
+ // mainly for tests
+ doc = new PlainDocument();
+ doc.putProperty("mimeType", mimeType);
+ }
+ return doc;
+ }
+ */
+}
diff --git a/api.templates/src/org/netbeans/modules/templates/TemplateProcessor2.java b/api.templates/src/org/netbeans/modules/templates/TemplateProcessor2.java
new file mode 100644
--- /dev/null
+++ b/api.templates/src/org/netbeans/modules/templates/TemplateProcessor2.java
@@ -0,0 +1,174 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development and
+ * Distribution License("CDDL") (collectively, the "License"). You may not use
+ * this file except in compliance with the License. You can obtain a copy of
+ * the License at http://www.netbeans.org/cddl-gplv2.html or
+ * nbbuild/licenses/CDDL-GPL-2-CP. See the License for the specific language
+ * governing permissions and limitations under the License. When distributing
+ * the software, include this License Header Notice in each file and include
+ * the License file at nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided by
+ * Oracle in the GPL Version 2 section of the License file that accompanied
+ * this code. If applicable, add the following below the License Header, with
+ * the fields enclosed by brackets [] replaced by your own identifying
+ * information: "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you do not indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to its
+ * licensees as provided above. However, if you add GPL Version 2 code and
+ * therefore, elected the GPL Version 2 license, then the option applies only
+ * if the new code is made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2011 Sun Microsystems, Inc.
+ */
+
+package org.netbeans.modules.templates;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+import javax.annotation.processing.Processor;
+import javax.annotation.processing.RoundEnvironment;
+import javax.annotation.processing.SupportedSourceVersion;
+import javax.lang.model.SourceVersion;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ElementKind;
+import javax.lang.model.element.TypeElement;
+import org.openide.filesystems.annotations.LayerGenerationException;
+import org.netbeans.api.templates.TemplateRegistration;
+import org.netbeans.api.templates.TemplateRegistrations;
+import org.openide.filesystems.annotations.LayerBuilder;
+import org.openide.filesystems.annotations.LayerGeneratingProcessor;
+import org.openide.util.lookup.ServiceProvider;
+
+/**
+ * The implementation has moved from data systems. Part of the implementation is still there,
+ * as the {@code InstantiatingIterator} support requires
+ * @author sdedic
+ */
+@ServiceProvider(service=Processor.class)
+@SupportedSourceVersion(SourceVersion.RELEASE_7)
+public class TemplateProcessor2 extends LayerGeneratingProcessor {
+
+ @Override public Set getSupportedAnnotationTypes() {
+ return new HashSet(Arrays.asList(TemplateRegistration.class.getCanonicalName(), TemplateRegistrations.class.getCanonicalName()));
+ }
+
+ @Override protected boolean handleProcess(Set extends TypeElement> annotations, RoundEnvironment roundEnv) throws LayerGenerationException {
+ if (roundEnv.processingOver()) {
+ return false;
+ }
+ for (Element e : roundEnv.getElementsAnnotatedWith(TemplateRegistration.class)) {
+ TemplateRegistration r = e.getAnnotation(TemplateRegistration.class);
+ if (r == null) {
+ continue;
+ }
+ process(e, r);
+ }
+ for (Element e : roundEnv.getElementsAnnotatedWith(TemplateRegistrations.class)) {
+ TemplateRegistrations rr = e.getAnnotation(TemplateRegistrations.class);
+ if (rr == null) {
+ continue;
+ }
+ for (TemplateRegistration t : rr.value()) {
+ process(e, t);
+ }
+ }
+ return false;
+ }
+
+ private void process(Element e, TemplateRegistration t) throws LayerGenerationException {
+ LayerBuilder builder = layer(e);
+ String basename;
+ if (!t.id().isEmpty()) {
+ if (t.content().length > 0) {
+ throw new LayerGenerationException("Cannot specify both id and content", e, processingEnv, t);
+ }
+ basename = t.id();
+ } else if (t.content().length > 0) {
+ basename = basename(t.content()[0]);
+ } else {
+ if (e.getKind() == ElementKind.CLASS) {
+ basename = ((TypeElement) e).getQualifiedName().toString().replace('.', '-');
+ } else if (e.getKind() == ElementKind.METHOD) {
+ basename = ((TypeElement) e.getEnclosingElement()).getQualifiedName().toString().replace('.', '-') + '-' + e.getSimpleName();
+ } else {
+ throw new LayerGenerationException("cannot use @Template on a package without specifying content", e, processingEnv, t);
+ }
+ }
+ String folder = "Templates/" + t.folder() + '/';
+ LayerBuilder.File f = builder.file(folder + basename);
+ f.boolvalue("template", true);
+ f.position(t.position());
+ if (!t.displayName().isEmpty()) {
+ f.bundlevalue("displayName", t.displayName());
+ }
+ if (!t.iconBase().isEmpty()) {
+ builder.validateResource(t.iconBase(), e, t, "iconBase", true);
+ f.stringvalue("iconBase", t.iconBase());
+ } else if (t.content().length == 0) {
+ throw new LayerGenerationException("Must specify iconBase if content is not specified", e, processingEnv, t);
+ }
+ if (!t.description().isEmpty()) {
+ f.urlvalue("instantiatingWizardURL", contentURI(e, t.description(), builder, t, "description"));
+ }
+// if (e.getKind() != ElementKind.PACKAGE) {
+// f.instanceAttribute("instantiatingIterator", InstantiatingIterator.class);
+// }
+ if (t.content().length > 0) {
+ f.url(contentURI(e, t.content()[0], builder, t, "content").toString());
+ for (int i = 1; i < t.content().length; i++) {
+ builder.file(folder + basename(t.content()[i])).url(contentURI(e, t.content()[i], builder, t, "content").toString()).position(0).write();
+ }
+ }
+ if (!t.scriptEngine().isEmpty()) {
+ f.stringvalue(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, t.scriptEngine());
+ }
+ if (t.category().length > 0) {
+ StringBuilder sb = new StringBuilder();
+ for (String c : t.category()) {
+ if (sb.length() > 0) {
+ sb.append(',');
+ }
+ sb.append(c);
+ }
+ f.stringvalue("templateCategory", sb.toString());
+ }
+ f.boolvalue("requireProject", t.requireProject());
+ if (!t.targetName().trim().isEmpty()) {
+ f.bundlevalue("targetName", t.targetName()); //NOI18N
+ }
+ f.write();
+ }
+
+ private static String basename(String relativeResource) {
+ return relativeResource.replaceFirst(".+/", "").replaceFirst("[.]template$", "");
+ }
+
+ private URI contentURI(Element e, String relativePath, LayerBuilder builder, TemplateRegistration t, String annotationMethod) throws LayerGenerationException {
+ String path = LayerBuilder.absolutizeResource(e, relativePath);
+ builder.validateResource(path, e, t, annotationMethod, false);
+ try {
+ return new URI("nbresloc", "/" + path, null).normalize();
+ } catch (URISyntaxException x) {
+ throw new LayerGenerationException("could not translate " + path, e, processingEnv, t);
+ }
+ }
+
+}
diff --git a/api.templates/test/unit/data/golden/ClassWithoutReplacements.java b/api.templates/test/unit/data/golden/ClassWithoutReplacements.java
new file mode 100644
--- /dev/null
+++ b/api.templates/test/unit/data/golden/ClassWithoutReplacements.java
@@ -0,0 +1,7 @@
+/**
+ *
+ * @author sdedic
+ */
+public class Templateclass1 {
+
+}
diff --git a/api.templates/test/unit/data/golden/ForceNoReplacements.java b/api.templates/test/unit/data/golden/ForceNoReplacements.java
new file mode 100644
--- /dev/null
+++ b/api.templates/test/unit/data/golden/ForceNoReplacements.java
@@ -0,0 +1,7 @@
+/**
+ *
+ * @author __USER__
+ */
+public class Templateclass1 {
+
+}
diff --git a/api.templates/test/unit/data/golden/GeneratedMethodBody.java b/api.templates/test/unit/data/golden/GeneratedMethodBody.java
new file mode 100644
--- /dev/null
+++ b/api.templates/test/unit/data/golden/GeneratedMethodBody.java
@@ -0,0 +1,2 @@
+return 42;
+
diff --git a/api.templates/test/unit/data/golden/GeneratedMethodBody2.java b/api.templates/test/unit/data/golden/GeneratedMethodBody2.java
new file mode 100644
--- /dev/null
+++ b/api.templates/test/unit/data/golden/GeneratedMethodBody2.java
@@ -0,0 +1,2 @@
+return 24;
+
diff --git a/api.templates/test/unit/data/golden/SimpleReplacements.java b/api.templates/test/unit/data/golden/SimpleReplacements.java
new file mode 100644
--- /dev/null
+++ b/api.templates/test/unit/data/golden/SimpleReplacements.java
@@ -0,0 +1,7 @@
+/**
+ *
+ * @author foobar
+ */
+public class Templateclass1 {
+
+}
diff --git a/api.templates/test/unit/data/templates/ClassWithoutReplacements.java b/api.templates/test/unit/data/templates/ClassWithoutReplacements.java
new file mode 100644
--- /dev/null
+++ b/api.templates/test/unit/data/templates/ClassWithoutReplacements.java
@@ -0,0 +1,7 @@
+/**
+ *
+ * @author sdedic
+ */
+public class Templateclass1 {
+
+}
diff --git a/api.templates/test/unit/data/templates/GeneratedMethodBody.java b/api.templates/test/unit/data/templates/GeneratedMethodBody.java
new file mode 100644
--- /dev/null
+++ b/api.templates/test/unit/data/templates/GeneratedMethodBody.java
@@ -0,0 +1,14 @@
+<#--
+A built-in Freemarker template (see http://freemarker.sourceforge.net) used for
+filling the body of methods generated by the IDE. When editing the template,
+the following predefined variables, that will be then expanded into
+the corresponding values, could be used together with Java expressions and
+comments:
+${method_return_type} a return type of a created method
+${default_return_value} a value returned by the method by default
+${method_name} name of the created method
+${class_name} qualified name of the enclosing class
+${simple_class_name} simple name of the enclosing class
+-->
+return ${default_return_value};
+
diff --git a/api.templates/test/unit/data/templates/SimpleReplacements.java b/api.templates/test/unit/data/templates/SimpleReplacements.java
new file mode 100644
--- /dev/null
+++ b/api.templates/test/unit/data/templates/SimpleReplacements.java
@@ -0,0 +1,7 @@
+/**
+ *
+ * @author __USER__
+ */
+public class Templateclass1 {
+
+}
diff --git a/api.templates/test/unit/src/org/netbeans/api/templates/TemplateUtilsTest.java b/api.templates/test/unit/src/org/netbeans/api/templates/TemplateUtilsTest.java
new file mode 100644
--- /dev/null
+++ b/api.templates/test/unit/src/org/netbeans/api/templates/TemplateUtilsTest.java
@@ -0,0 +1,177 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2014 Sun Microsystems, Inc.
+ */
+package org.netbeans.api.templates;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.netbeans.junit.NbTestCase;
+import org.netbeans.modules.templates.ScriptingCreateFromTemplateHandler;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.util.lookup.Lookups;
+import org.openide.util.test.MockLookup;
+
+/**
+ *
+ * @author sdedic
+ */
+public class TemplateUtilsTest extends NbTestCase {
+
+ public TemplateUtilsTest(String name) {
+ super(name);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ clearWorkDir();
+ }
+
+ /**
+ * Checks creation of templates without any special processing.
+ * @throws Exception
+ */
+ public void testCreatePlain() throws Exception {
+ FileObject dataRoot = FileUtil.toFileObject(getDataDir());
+ FileObject template = dataRoot.getFileObject("templates/ClassWithoutReplacements.java");
+ template.setAttribute("template", Boolean.TRUE);
+ FileObject workRoot = FileUtil.toFileObject(getWorkDir());
+ FileObject result = FileBuilder.createFromTemplate(template, workRoot, "NoReplacements", null, FileBuilder.Mode.FORMAT);
+ FileObject pass = dataRoot.getFileObject("golden/ClassWithoutReplacements.java");
+ assertFile(FileUtil.toFile(result), FileUtil.toFile(pass));
+ }
+
+ /**
+ * Forces plain default processing, although the template contains replaceable parts
+ */
+ public void testCreateForcePlain() throws Exception {
+ FileObject dataRoot = FileUtil.toFileObject(getDataDir());
+ FileObject template = dataRoot.getFileObject("templates/SimpleReplacements.java");
+ template.setAttribute("template", Boolean.TRUE);
+ FileObject workRoot = FileUtil.toFileObject(getWorkDir());
+ Map m = new HashMap();
+ m.put("USER", "foobar");
+ FileObject result = FileBuilder.createFromTemplate(template, workRoot, "NoReplacements", m, FileBuilder.Mode.COPY);
+ FileObject pass = dataRoot.getFileObject("golden/ForceNoReplacements.java");
+ assertFile(FileUtil.toFile(result), FileUtil.toFile(pass));
+ }
+
+ /**
+ * Uses a simple format, this is the mode applied by former implementation in MultiDataObject
+ */
+ public void testCreateReplaceSimple() throws Exception {
+ clearWorkDir();
+ FileObject dataRoot = FileUtil.toFileObject(getDataDir());
+ FileObject template = dataRoot.getFileObject("templates/SimpleReplacements.java");
+ template.setAttribute("template", Boolean.TRUE);
+ FileObject workRoot = FileUtil.toFileObject(getWorkDir());
+ Map m = new HashMap();
+ m.put("USER", "foobar");
+ FileObject result = FileBuilder.createFromTemplate(template, workRoot, "SimpleReplacements", m, FileBuilder.Mode.FORMAT);
+ FileObject pass = dataRoot.getFileObject("golden/SimpleReplacements.java");
+ assertFile(FileUtil.toFile(result), FileUtil.toFile(pass));
+ }
+
+ public void testScriptingTemplate() throws Exception {
+ clearWorkDir();
+ FileObject dataRoot = FileUtil.toFileObject(getDataDir());
+ FileObject template = dataRoot.getFileObject("templates/GeneratedMethodBody.java");
+ template.setAttribute("template", Boolean.TRUE);
+ template.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "freemarker");
+ FileObject workRoot = FileUtil.toFileObject(getWorkDir());
+ Map m = new HashMap();
+ m.put("default_return_value", "42");
+ FileObject result = FileBuilder.createFromTemplate(template, workRoot, "GeneratedMethodBody", m, FileBuilder.Mode.FORMAT);
+ FileObject pass = dataRoot.getFileObject("golden/GeneratedMethodBody.java");
+ assertFile(FileUtil.toFile(result), FileUtil.toFile(pass));
+ }
+
+ @SuppressWarnings("PackageVisibleInnerClass")
+ class DefaultValueAttribute implements CreateFromTemplateAttributes {
+ @Override
+ public Map attributesFor(CreateDescriptor desc) {
+ FileObject template = desc.getTemplate();
+ FileObject dataRoot = FileUtil.toFileObject(getDataDir());
+ FileObject t = dataRoot.getFileObject("templates/GeneratedMethodBody.java");
+ if (t != template) {
+ return null;
+ }
+
+ Map m = new HashMap();
+ m.put("default_return_value", "42");
+
+ return m;
+ }
+ }
+
+ public void testAddTemplateParameters() throws Exception {
+ MockLookup.setLookup(
+ Lookups.metaInfServices(getClass().getClassLoader()),
+ Lookups.fixed(new DefaultValueAttribute()));
+ clearWorkDir();
+ FileObject dataRoot = FileUtil.toFileObject(getDataDir());
+ FileObject template = dataRoot.getFileObject("templates/GeneratedMethodBody.java");
+ template.setAttribute("template", Boolean.TRUE);
+ template.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "freemarker");
+ FileObject workRoot = FileUtil.toFileObject(getWorkDir());
+ FileObject result = FileBuilder.createFromTemplate(template, workRoot, "GeneratedMethodBody", null, FileBuilder.Mode.FORMAT);
+ FileObject pass = dataRoot.getFileObject("golden/GeneratedMethodBody.java");
+ assertFile(FileUtil.toFile(result), FileUtil.toFile(pass));
+ }
+
+ public void testOverridenParameters() throws Exception {
+ MockLookup.setLookup(
+ Lookups.metaInfServices(getClass().getClassLoader()),
+ Lookups.fixed(new DefaultValueAttribute()));
+ clearWorkDir();
+ FileObject dataRoot = FileUtil.toFileObject(getDataDir());
+ FileObject template = dataRoot.getFileObject("templates/GeneratedMethodBody.java");
+ template.setAttribute("template", Boolean.TRUE);
+ template.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "freemarker");
+ FileObject workRoot = FileUtil.toFileObject(getWorkDir());
+ Map m = new HashMap();
+ m.put("default_return_value", "24");
+ FileObject result = FileBuilder.createFromTemplate(template, workRoot, "GeneratedMethodBody", m, FileBuilder.Mode.FORMAT);
+ FileObject pass = dataRoot.getFileObject("golden/GeneratedMethodBody2.java");
+ assertFile(FileUtil.toFile(result), FileUtil.toFile(pass));
+ }
+}
diff --git a/api.templates/test/unit/src/org/netbeans/modules/templates/Bug138973Test.java b/api.templates/test/unit/src/org/netbeans/modules/templates/Bug138973Test.java
new file mode 100644
--- /dev/null
+++ b/api.templates/test/unit/src/org/netbeans/modules/templates/Bug138973Test.java
@@ -0,0 +1,267 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2010 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2008 Sun Microsystems, Inc.
+ */
+
+package org.netbeans.modules.templates;
+
+import java.util.Enumeration;
+import org.openide.loaders.*;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Reader;
+import java.io.Writer;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CharsetEncoder;
+import java.nio.charset.CoderResult;
+import java.util.Map;
+import org.netbeans.api.editor.mimelookup.MimePath;
+import org.netbeans.api.editor.mimelookup.test.MockMimeLookup;
+import org.netbeans.api.queries.FileEncodingQuery;
+import org.netbeans.junit.MockServices;
+import org.netbeans.junit.NbTestCase;
+import org.netbeans.modules.openide.loaders.DataObjectEncodingQueryImplementation;
+import org.netbeans.modules.templates.ScriptingCreateFromTemplateHandler;
+import org.netbeans.spi.queries.FileEncodingQueryImplementation;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.util.Enumerations;
+import org.openide.util.Lookup;
+import org.openide.util.lookup.Lookups;
+
+/**
+ *
+ * @author Marian Petras
+ */
+public class Bug138973Test extends NbTestCase {
+
+ private static final String TESTING_TEXT = "print('This is a testing text.')";
+ private static final TestCharset TEST_CHARSET = new TestCharset();
+ private static final String EXT = ".test";
+ private static final String TEMPLATE_NAME = "Bug138973TestTemplate";
+ private static final String TEMPLATE_NAME_EXT = TEMPLATE_NAME + EXT;
+ private static final String TESTFILE_NAME = "testfile";
+ private static final String TESTFILE_NAME_EXT = TESTFILE_NAME + EXT;
+
+ public Bug138973Test(String n) {
+ super(n);
+ }
+
+ public void testBug() throws Exception {
+ MockServices.setServices(Pool.class, DataObjectEncodingQueryImplementation.class);
+ FileUtil.setMIMEType("test", "text/test");
+ MockMimeLookup.setInstances(MimePath.get("text/test"), new TestEncoding());
+// FileUtil.createData(FileUtil.getConfigRoot(), "Editors/text/test/" + TestEncoding.class.getName().replace('.', '-') + ".instance");
+
+ FileObject root = FileUtil.createMemoryFileSystem().getRoot();
+ FileObject templatesFolder = root.createFolder("templates");
+ assert templatesFolder != null;
+ FileObject templateFile = FileUtil.createData(templatesFolder,
+ TEMPLATE_NAME_EXT);
+ templateFile.setAttribute ("template", Boolean.TRUE);
+ templateFile.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
+ byte[] templateBytes = TESTING_TEXT.getBytes("ISO-8859-1");
+ InputStream source = new ByteArrayInputStream(templateBytes);
+ OutputStream target = templateFile.getOutputStream();
+ FileUtil.copy(source, target);
+ target.close();
+ source.close();
+ assert templateFile.getSize() != 0L;
+ templateFile.setAttribute("template", Boolean.TRUE);
+
+ assertEquals("text/test", templateFile.getMIMEType());
+
+ assertEquals("No Decoder yet", 0, TestCharset.newDecoder);
+ DataObject templateDataObj = DataObject.find(templateFile);
+ DataObject newDataObj= templateDataObj.createFromTemplate(
+ DataFolder.findFolder(root),
+ TESTFILE_NAME);
+
+ assertTrue("Decoder created", TestCharset.newDecoder >= 1);
+ }
+
+ public static final class SimpleTemplateHandler extends CreateFromTemplateHandler {
+ @Override
+ public boolean accept(FileObject orig) {
+ return true;
+ }
+ @Override
+ public FileObject createFromTemplate(FileObject template,
+ FileObject targetFolder,
+ String name,
+ Map parameters) throws IOException {
+ String nameUniq = FileUtil.findFreeFileName(targetFolder, name, template.getExt());
+ FileObject newFile = FileUtil.createData(targetFolder, nameUniq + '.' + template.getExt());
+
+ Charset templateEnc = FileEncodingQuery.getEncoding(template);
+ Charset newFileEnc = FileEncodingQuery.getEncoding(newFile);
+
+ InputStream is = template.getInputStream();
+ Reader reader = new BufferedReader(new InputStreamReader(is, templateEnc));
+ OutputStream os = newFile.getOutputStream();
+ Writer writer = new BufferedWriter(new OutputStreamWriter(os, newFileEnc));
+ int cInt;
+ while ((cInt = reader.read()) != -1) {
+ writer.write(cInt);
+ }
+ writer.close();
+ reader.close();
+
+ return newFile;
+ }
+ }
+
+ public static final class SimpleLoader extends MultiFileLoader {
+ public SimpleLoader() {
+ super(SimpleObject.class.getName());
+ }
+ protected String displayName() {
+ return "SimpleLoader";
+ }
+ @Override
+ protected FileObject findPrimaryFile(FileObject fo) {
+ if (fo.getNameExt().equals(TEMPLATE_NAME_EXT)) {
+ return fo;
+ }
+ if (fo.getNameExt().equals(TESTFILE_NAME_EXT)) {
+ return fo;
+ }
+ return null;
+ }
+ @Override
+ protected MultiDataObject createMultiObject(FileObject primaryFile)
+ throws DataObjectExistsException,
+ IOException {
+ return new SimpleObject(this, primaryFile, isTestingFile(primaryFile));
+ }
+ @Override
+ protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj,
+ FileObject primaryFile) {
+ return new FE(obj, primaryFile);
+ }
+ @Override
+ protected MultiDataObject.Entry createSecondaryEntry(MultiDataObject obj,
+ FileObject secondaryFile) {
+ return new FE(obj, secondaryFile);
+ }
+ private static boolean isTestingFile(FileObject fileObj) {
+ return fileObj.getNameExt().equals(TESTFILE_NAME_EXT);
+ }
+ }
+
+ private static final class FE extends FileEntry {
+ public FE(MultiDataObject mo, FileObject fo) {
+ super(mo, fo);
+ }
+ @Override
+ public FileObject createFromTemplate(FileObject f, String name) throws IOException {
+ fail("FileEntry.createFromTemplate() should not be called");
+ return null;
+ }
+ }
+
+ public static final class SimpleObject extends MultiDataObject {
+ private final Lookup lookup;
+ public SimpleObject(SimpleLoader l,
+ FileObject fo,
+ boolean useSpecialEncoding)
+ throws DataObjectExistsException {
+ super(fo, l);
+ lookup = useSpecialEncoding
+ ? Lookups.fixed(this, new TestEncoding())
+ : Lookups.singleton(this);
+ }
+ @Override
+ public String getName() {
+ return getPrimaryFile().getNameExt();
+ }
+ @Override
+ public Lookup getLookup() {
+ return lookup;
+ }
+ }
+
+ public static final class TestEncoding extends FileEncodingQueryImplementation {
+ @Override
+ public Charset getEncoding(FileObject file) {
+ return TEST_CHARSET;
+ }
+ }
+
+ static final class TestCharset extends Charset {
+ static int newDecoder;
+ static int newEncoder;
+
+ TestCharset() {
+ super("test_charset", null);
+ }
+ @Override
+ public boolean contains(Charset charset) {
+ return true;
+ }
+ @Override
+ public CharsetDecoder newDecoder() {
+ newDecoder++;
+ return Charset.forName("UTF-8").newDecoder();
+ }
+ @Override
+ public CharsetEncoder newEncoder() {
+ newEncoder++;
+ return Charset.forName("UTF-8").newEncoder();
+ }
+ }
+
+ public static final class Pool extends DataLoaderPool {
+ @Override
+ protected Enumeration extends DataLoader> loaders() {
+ return Enumerations.singleton(SimpleLoader.getLoader(SimpleLoader.class));
+ }
+
+ }
+}
\ No newline at end of file
diff --git a/api.templates/test/unit/src/org/netbeans/modules/templates/CreateFromTemplateHandlerTest.java b/api.templates/test/unit/src/org/netbeans/modules/templates/CreateFromTemplateHandlerTest.java
new file mode 100644
--- /dev/null
+++ b/api.templates/test/unit/src/org/netbeans/modules/templates/CreateFromTemplateHandlerTest.java
@@ -0,0 +1,238 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc.
+ *
+ * Portions Copyrighted 2007 Sun Microsystems, Inc.
+ */
+
+package org.netbeans.modules.templates;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.netbeans.api.templates.CreateDescriptor;
+import org.netbeans.api.templates.CreateFromTemplateAttributes;
+import org.netbeans.junit.MockServices;
+import org.netbeans.junit.NbTestCase;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.loaders.CreateFromTemplateHandler;
+import org.openide.loaders.DataFolder;
+import org.openide.loaders.DataLoader;
+import org.openide.loaders.DataLoaderPool;
+import org.openide.loaders.DataObject;
+import org.openide.loaders.DataObjectExistsException;
+import org.openide.loaders.FileEntry;
+import org.openide.loaders.MultiDataObject;
+import org.openide.loaders.MultiFileLoader;
+import org.openide.util.Enumerations;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class CreateFromTemplateHandlerTest extends NbTestCase {
+
+ public CreateFromTemplateHandlerTest(String testName) {
+ super(testName);
+ }
+
+ protected boolean runInEQ() {
+ return true;
+ }
+
+ protected void setUp() throws Exception {
+ Hand.acceptObject = new ArrayList();
+ Hand.fileObject = new ArrayList();
+ Hand.origObject = new ArrayList();
+ Hand.name = null;
+ Hand.parameters = null;
+
+ MockServices.setServices(Hand.class, Attr.class, Pool.class);
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ public void testCreateFromTemplate() throws Exception {
+ FileObject root = FileUtil.createMemoryFileSystem().getRoot();
+ FileObject fo = FileUtil.createData(root, "simpleObject.txt");
+
+ DataObject obj = DataObject.find(fo);
+
+ DataFolder folder = DataFolder.findFolder(FileUtil.createFolder(root, "target"));
+
+ Map parameters = Collections.singletonMap("type", "empty");
+ DataObject n = obj.createFromTemplate(folder, "complex", parameters);
+
+ assertEquals("Created in right place", folder, n.getFolder());
+ assertEquals("Created with right name", "complex.txt", n.getName());
+
+ assertEquals("The right source", fo, Hand.origObject.get(0));
+ assertEquals("The right source in query", fo, Hand.acceptObject.get(0));
+ assertEquals("The right destiny folder", folder.getPrimaryFile(), Hand.fileObject.get(0));
+ assertEquals("The right name", "complex", Hand.name);
+ if (Hand.parameters.size() < 2) {
+ fail("As least two: " + Hand.parameters + " but was " + Hand.parameters.size());
+ }
+ assertEquals("empty", Hand.parameters.get("type"));
+ assertEquals("complex", Hand.parameters.get("name"));
+ try {
+ Hand.parameters.put("kuk", "buk");
+ } catch (UnsupportedOperationException ex) {
+ // ok
+ return;
+ }
+ fail("Modifications shall be unsupported");
+ }
+
+ public static final class Hand extends CreateFromTemplateHandler {
+ public static List fileObject, origObject, acceptObject;
+ public static String name;
+ public static Map parameters;
+
+ public boolean accept(FileObject fo) {
+ acceptObject.add(fo);
+ return true;
+ }
+
+ public FileObject createFromTemplate(
+ FileObject orig, FileObject f, String n,
+ Map p
+ ) throws IOException {
+ origObject.add(orig);
+ fileObject.add(f);
+ name = n;
+ parameters = p;
+
+ return FileUtil.copyFile(orig, f, name);
+ }
+ }
+
+ public static final class Attr implements CreateFromTemplateAttributes {
+ @Override
+ public Map attributesFor(CreateDescriptor desc) {
+ return Collections.singletonMap("name", desc.getProposedName());
+ }
+ }
+
+ public static final class Pool extends DataLoaderPool {
+ protected Enumeration loaders() {
+ return Enumerations.array(new DataLoader[] {
+ SimpleLoader.getLoader(SimpleLoader.class),
+ TwoPartLoader.getLoader(TwoPartLoader.class),
+ });
+ }
+ }
+
+ public static final class SimpleLoader extends MultiFileLoader {
+ public SimpleLoader() {
+ super(SimpleObject.class.getName());
+ }
+ protected String displayName() {
+ return "SimpleLoader";
+ }
+ protected FileObject findPrimaryFile(FileObject fo) {
+ if (fo.hasExt("prima")) {
+ return fo;
+ }
+ return null;
+ }
+ protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException {
+ return new SimpleObject(this, primaryFile);
+ }
+ protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj, FileObject primaryFile) {
+ return new FE(obj, primaryFile);
+ }
+ protected MultiDataObject.Entry createSecondaryEntry(MultiDataObject obj, FileObject secondaryFile) {
+ return new FileEntry(obj, secondaryFile);
+ }
+ }
+
+ private static final class FE extends FileEntry {
+ public FE(MultiDataObject mo, FileObject fo) {
+ super(mo, fo);
+ }
+
+ @Override
+ public FileObject createFromTemplate(FileObject f, String name) throws IOException {
+ fail("I do not want to be called");
+ return null;
+ }
+ }
+
+ public static final class SimpleObject extends MultiDataObject {
+ public SimpleObject(SimpleLoader l, FileObject fo) throws DataObjectExistsException {
+ super(fo, l);
+ }
+
+ public String getName() {
+ return getPrimaryFile().getNameExt();
+ }
+ }
+
+
+
+ public static final class TwoPartLoader extends MultiFileLoader {
+ public TwoPartLoader() {
+ super(TwoPartObject.class.getName ());
+ }
+ protected String displayName() {
+ return "TwoPart";
+ }
+ protected FileObject findPrimaryFile(FileObject fo) {
+ if (fo.hasExt("java") || fo.hasExt("form")) {
+ return org.openide.filesystems.FileUtil.findBrother(fo, "java");
+ } else {
+ return null;
+ }
+ }
+ protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException {
+ return new TwoPartObject(this, primaryFile);
+ }
+ protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj, FileObject primaryFile) {
+ return new FE(obj, primaryFile);
+ }
+ protected MultiDataObject.Entry createSecondaryEntry(MultiDataObject obj, FileObject secondaryFile) {
+ return new FE(obj, secondaryFile);
+ }
+ }
+ public static final class TwoPartObject extends MultiDataObject {
+ public TwoPartObject(TwoPartLoader l, FileObject folder) throws DataObjectExistsException {
+ super(folder, l);
+ }
+ }
+
+}
diff --git a/api.templates/test/unit/src/org/netbeans/modules/templates/IndentEngineIntTest.java b/api.templates/test/unit/src/org/netbeans/modules/templates/IndentEngineIntTest.java
new file mode 100644
--- /dev/null
+++ b/api.templates/test/unit/src/org/netbeans/modules/templates/IndentEngineIntTest.java
@@ -0,0 +1,247 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc.
+ *
+ * Portions Copyrighted 2007 Sun Microsystems, Inc.
+ */
+
+package org.netbeans.modules.templates;
+
+import java.awt.Dialog;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.Map;
+import javax.swing.text.BadLocationException;
+import org.netbeans.api.editor.mimelookup.MimePath;
+import org.netbeans.api.editor.mimelookup.test.MockMimeLookup;
+import org.netbeans.api.templates.FileBuilder;
+import org.netbeans.junit.NbTestCase;
+import org.netbeans.modules.editor.indent.spi.Context;
+import org.netbeans.modules.editor.indent.spi.ExtraLock;
+import org.netbeans.modules.editor.indent.spi.ReformatTask;
+import org.openide.DialogDescriptor;
+import org.openide.DialogDisplayer;
+import org.openide.NotifyDescriptor;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.loaders.DataFolder;
+import org.openide.loaders.DataLoader;
+import org.openide.loaders.DataLoaderPool;
+import org.openide.loaders.DataObject;
+import org.openide.loaders.DataObjectExistsException;
+import org.openide.loaders.FileEntry;
+import org.openide.loaders.MultiDataObject;
+import org.openide.loaders.MultiFileLoader;
+import org.openide.util.Enumerations;
+import org.openide.util.lookup.Lookups;
+import org.openide.util.test.MockLookup;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class IndentEngineIntTest extends NbTestCase {
+
+ public IndentEngineIntTest(String testName) {
+ super(testName);
+ }
+
+ protected boolean runInEQ() {
+ return true;
+ }
+
+
+ @SuppressWarnings("deprecation")
+ protected void setUp() throws Exception {
+ MockLookup.setLookup(Lookups.fixed(new DD(), new Pool()), Lookups.metaInfServices(getClass().getClassLoader()));
+ MockMimeLookup.setInstances(MimePath.get("text/jarda"), new IEImpl2());
+ FileUtil.setMIMEType("txt", "text/jarda");
+ clearWorkDir();
+ super.setUp();
+ }
+
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ /**
+ * Checks that the templating works without IndentEngine available
+ * @throws Exception
+ */
+ public void testWithoutEditorIndent() throws Exception {
+ MockLookup.setLookup(Lookups.fixed(new DD(), new Pool()),
+ Lookups.exclude(Lookups.metaInfServices(getClass().getClassLoader()),
+ Class.forName("org.netbeans.modules.editor.indent.IndentScriptEngineHack$Factory")
+ ));
+ FileObject dataRoot = FileUtil.toFileObject(getDataDir());
+ FileObject template = dataRoot.getFileObject("templates/ClassWithoutReplacements.java");
+ template.setAttribute("template", Boolean.TRUE);
+ FileObject workRoot = FileUtil.toFileObject(getWorkDir());
+ FileObject result = FileBuilder.createFromTemplate(template, workRoot, "NoReplacements", null, FileBuilder.Mode.FORMAT);
+ FileObject pass = dataRoot.getFileObject("golden/ClassWithoutReplacements.java");
+ assertFile(FileUtil.toFile(result), FileUtil.toFile(pass));
+ }
+
+ public void testCreateFromTemplateUsingFreemarker() throws Exception {
+ FileObject root = FileUtil.createMemoryFileSystem().getRoot();
+ FileObject fo = FileUtil.createData(root, "simpleObject.txt");
+ OutputStream os = fo.getOutputStream();
+ String txt = "print('
'); print(title); print('
');";
+ os.write(txt.getBytes());
+ os.close();
+ fo.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "JavaScript");
+
+
+ DataObject obj = DataObject.find(fo);
+
+ DataFolder folder = DataFolder.findFolder(FileUtil.createFolder(root, "target"));
+
+ Map parameters = Collections.singletonMap("title", "Nazdar");
+ DataObject n = obj.createFromTemplate(folder, "complex", parameters);
+
+ assertEquals("Created in right place", folder, n.getFolder());
+ assertEquals("Created with right name", "complex.txt", n.getName());
+
+ String exp = ">lmth/<>1h/1h<>lmth<";
+ assertEquals(exp, stripNewLines(readFile(n.getPrimaryFile())));
+
+ }
+
+ static String stripNewLines(String str) {
+ return str.replace("\n", "").replace("\r", "");
+ }
+
+ private static String readFile(FileObject fo) throws IOException {
+ return fo.asText();
+ }
+
+ public static final class DD extends DialogDisplayer {
+ public Object notify(NotifyDescriptor descriptor) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public Dialog createDialog(final DialogDescriptor descriptor) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+ }
+
+ public static final class Pool extends DataLoaderPool {
+ protected Enumeration loaders() {
+ return Enumerations.singleton(SimpleLoader.getLoader(SimpleLoader.class));
+ }
+ }
+
+ public static final class SimpleLoader extends MultiFileLoader {
+ public SimpleLoader() {
+ super(SimpleObject.class.getName());
+ }
+ protected String displayName() {
+ return "SimpleLoader";
+ }
+ protected FileObject findPrimaryFile(FileObject fo) {
+ if (fo.hasExt("prima")) {
+ return fo;
+ }
+ return null;
+ }
+ protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException {
+ return new SimpleObject(this, primaryFile);
+ }
+ protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj, FileObject primaryFile) {
+ return new FE(obj, primaryFile);
+ }
+ protected MultiDataObject.Entry createSecondaryEntry(MultiDataObject obj, FileObject secondaryFile) {
+ return new FileEntry(obj, secondaryFile);
+ }
+ }
+
+ private static final class FE extends FileEntry {
+ public FE(MultiDataObject mo, FileObject fo) {
+ super(mo, fo);
+ }
+
+ @Override
+ public FileObject createFromTemplate(FileObject f, String name) throws IOException {
+ fail("I do not want to be called");
+ return null;
+ }
+
+
+
+ }
+
+ public static final class SimpleObject extends MultiDataObject {
+ public SimpleObject(SimpleLoader l, FileObject fo) throws DataObjectExistsException {
+ super(fo, l);
+ }
+
+ public String getName() {
+ return getPrimaryFile().getNameExt();
+ }
+ }
+
+ public static final class IEImpl2 implements ReformatTask, ReformatTask.Factory {
+ private Context context;
+
+ public IEImpl2(Context context) {
+ this.context = context;
+ }
+
+ public IEImpl2() {
+ }
+
+ @Override
+ public void reformat() throws BadLocationException {
+ int from = context.startOffset();
+ int to = context.endOffset();
+ int len = to - from;
+ String s = context.document().getText(from, len);
+ StringBuilder sb = new StringBuilder(s.length());
+ for (int i = s.length() - 1; i >= 0; i--) {
+ sb.append(s.charAt(i));
+ }
+ context.document().insertString(from, sb.toString(), null);
+ context.document().remove(from + len, len);
+ }
+
+ @Override
+ public ExtraLock reformatLock() {
+ return null;
+ }
+
+ @Override
+ public ReformatTask createTask(Context context) {
+ return new IEImpl2(context);
+ }
+ }
+
+}
diff --git a/api.templates/test/unit/src/org/netbeans/modules/templates/SCFTHandlerTest.java b/api.templates/test/unit/src/org/netbeans/modules/templates/SCFTHandlerTest.java
new file mode 100644
--- /dev/null
+++ b/api.templates/test/unit/src/org/netbeans/modules/templates/SCFTHandlerTest.java
@@ -0,0 +1,507 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc.
+ *
+ * Portions Copyrighted 2007 Sun Microsystems, Inc.
+ */
+
+package org.netbeans.modules.templates;
+
+import java.awt.Dialog;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.netbeans.junit.MockServices;
+import org.netbeans.junit.NbTestCase;
+import org.netbeans.spi.queries.FileEncodingQueryImplementation;
+import org.openide.DialogDescriptor;
+import org.openide.DialogDisplayer;
+import org.openide.NotifyDescriptor;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileStateInvalidException;
+import org.openide.filesystems.FileSystem;
+import org.openide.filesystems.FileUtil;
+import org.openide.filesystems.LocalFileSystem;
+import org.openide.loaders.DataFolder;
+import org.openide.loaders.DataLoader;
+import org.openide.loaders.DataLoaderPool;
+import org.openide.loaders.DataObject;
+import org.openide.loaders.DataObjectExistsException;
+import org.openide.loaders.FileEntry;
+import org.openide.loaders.MultiDataObject;
+import org.openide.loaders.MultiFileLoader;
+import org.openide.util.Enumerations;
+
+/**
+ *
+ * @author Jaroslav Tulach
+ */
+public class SCFTHandlerTest extends NbTestCase {
+ static {
+ // confuse the system a bit, if your system runs with UTF-8 default locale...
+ //System.setProperty("file.encoding", "cp1252");
+ }
+
+ public SCFTHandlerTest(String testName) {
+ super(testName);
+ }
+
+ @Override
+ protected boolean runInEQ() {
+ return true;
+ }
+
+ @Override
+ protected Level logLevel() {
+ return Level.FINE;
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ clearWorkDir();
+ MockServices.setServices(DD.class, Pool.class, FEQI.class);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+ public void testCreateFromTemplateUsingFreemarker() throws Exception {
+ FileObject root = FileUtil.createMemoryFileSystem().getRoot();
+ FileObject fo = FileUtil.createData(root, "simpleObject.txt");
+ OutputStream os = fo.getOutputStream();
+ String txt = "print('
');" +
+ "print('');";
+ os.write(txt.getBytes());
+ os.close();
+ fo.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
+
+
+ DataObject obj = DataObject.find(fo);
+
+ DataFolder folder = DataFolder.findFolder(FileUtil.createFolder(root, "target"));
+
+ Map parameters = Collections.singletonMap("title", "Nazdar");
+ DataObject n = obj.createFromTemplate(folder, "complex", parameters);
+
+ assertEquals("Created in right place", folder, n.getFolder());
+ assertEquals("Created with right name", "complex.txt", n.getName());
+
+ String res = readFile(n.getPrimaryFile());
+
+ if (res.indexOf("date") >= 0) fail(res);
+ if (res.indexOf("time") >= 0) fail(res);
+ if (res.indexOf("user") >= 0) fail(res);
+ if (res.indexOf("name") >= 0) fail(res);
+ if (res.indexOf("dateTime") >= 0) fail(res);
+ }
+
+ private static String readFile(FileObject fo) throws IOException {
+ byte[] arr = new byte[(int)fo.getSize()];
+ int len = fo.getInputStream().read(arr);
+ assertEquals("Fully read", arr.length, len);
+ return new String(arr);
+ }
+
+ private static String readChars(FileObject fo, Charset set) throws IOException {
+ CharBuffer arr = CharBuffer.allocate((int)fo.getSize() * 2);
+ BufferedReader r = new BufferedReader(new InputStreamReader(fo.getInputStream(), set));
+ while (r.read(arr) != -1) {
+ // again
+ }
+ r.close();
+
+ arr.flip();
+ return arr.toString();
+ }
+
+ public void testUTF8() throws Exception {
+ FileObject root = FileUtil.getConfigRoot();
+ FileObject xmldir = FileUtil.createFolder(root, "xml");
+ FileObject xml = FileUtil.createData(xmldir, "class.txt");
+ OutputStream os = xml.getOutputStream();
+ FileUtil.copy(getClass().getResourceAsStream("utf8.xml"), os);
+ xml.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
+ os.close();
+
+ DataObject obj = DataObject.find(xml);
+
+
+ FileObject target = FileUtil.createFolder(FileUtil.createMemoryFileSystem().getRoot(), "dir");
+ DataFolder folder = DataFolder.findFolder(FileUtil.createFolder(target, "target"));
+
+
+
+ Charset set = Charset.forName("iso-8859-2");
+ FEQI.fs = target.getFileSystem();
+ FEQI.result = set;
+
+
+ Map parameters = Collections.singletonMap("title", "Nazdar");
+ DataObject n = obj.createFromTemplate(folder, "complex", parameters);
+
+ assertEquals("Created in right place", folder, n.getFolder());
+ assertEquals("Created with right name", "complex.txt", n.getName());
+
+
+ String read = readChars(n.getPrimaryFile(), set).replaceAll("println\\('", "").replaceAll("'\\);", "");
+ String exp = readChars(xml, Charset.forName("utf-8")).replaceAll("println\\('", "").replaceAll("'\\);", "");
+ assertEquals(exp, read);
+
+ }
+
+ public void testTemplateWizardCopiesItsPropertiesToMapForOverridenEntryOnMoreEntries() throws Exception {
+ LocalFileSystem fs = new LocalFileSystem();
+ fs.setRootDirectory(getWorkDir());
+
+ FileObject root = fs.getRoot();
+ FileObject fo = FileUtil.createData(root, "simpleObject.java");
+ FileObject fo2 = FileUtil.createData(root, "simpleObject.form");
+ fo.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
+ fo2.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
+
+ Charset set = Charset.forName("iso-8859-2");
+ OutputStream os = fo2.getOutputStream();
+ OutputStreamWriter w = new OutputStreamWriter(os, set);
+ String txt = "print('skvělej tým, co nikdy neusíná - ěščřžýáíéúů')";
+ w.write(txt);
+ w.close();
+
+
+ DataObject obj = DataObject.find(fo);
+ assertEquals(TwoPartObject.class, obj.getClass());
+ TwoPartObject tpo = (TwoPartObject)obj;
+ tpo.encoding = set;
+
+ FileObject root2 = FileUtil.createMemoryFileSystem().getRoot();
+ DataFolder folder = DataFolder.findFolder(FileUtil.createFolder(root2, "target"));
+
+ Map parameters = Collections.singletonMap("type", "empty");
+
+ FEQI.fs = root2.getFileSystem();
+ FEQI.result = Charset.forName("UTF-8");
+
+ DataObject n = obj.createFromTemplate(folder, "complex", parameters);
+ Integer cnt = TwoPartLoader.queried.get(n.getPrimaryFile());
+ assertEquals("No query", null, cnt);
+
+ assertEquals("Created in right place", folder, n.getFolder());
+ assertEquals("Created with right name", "complex", n.getName());
+ Iterator it = n.files().iterator();
+ it.next();
+ FileObject snd = it.next();
+
+ long length = snd.getSize();
+ if (length <= 0) {
+ fail("Too small file: " + length + " for " + snd);
+ }
+ InputStream is = snd.getInputStream();
+ InputStreamReader r = new InputStreamReader(is, "UTF-8");
+ char[] cbuf = new char[1024];
+ int len = r.read(cbuf);
+ if (len == -1) {
+ fail("no input stream for " + snd);
+ }
+ String read = new String(cbuf, 0, len);
+ txt = txt.replaceAll("print\\('", "").replaceAll("'\\)", "");
+
+ assertEquals(txt, read);
+ }
+
+ public static final class DD extends DialogDisplayer {
+ public Object notify(NotifyDescriptor descriptor) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public Dialog createDialog(final DialogDescriptor descriptor) {
+ throw new UnsupportedOperationException("Not supported yet.");
+ /*
+ return new JDialog() {
+ @Deprecated
+ public void show() {
+ for (Object object : descriptor.getOptions()) {
+ if (object instanceof JButton) {
+ JButton b = (JButton)object;
+ if (b.getText().equals("Finish")) {
+ descriptor.setValue(WizardDescriptor.FINISH_OPTION);
+ b.doClick();
+ return;
+ }
+ }
+ }
+ fail("Cannot find Finish button: " + Arrays.asList(descriptor.getOptions()));
+ }
+ };
+ */
+ }
+ }
+
+ public static final class FEQI extends FileEncodingQueryImplementation {
+ public static FileSystem fs;
+ public static Charset result;
+
+ public Charset getEncoding(FileObject f) {
+ try {
+ if (f.getFileSystem() == fs) {
+ return result;
+ }
+ return null;
+ } catch (FileStateInvalidException ex) {
+ return null;
+ }
+ }
+ }
+
+ public static final class Pool extends DataLoaderPool {
+ protected Enumeration loaders() {
+ return Enumerations.array(new DataLoader[] {
+ TwoPartLoader.getLoader(TwoPartLoader.class),
+ SimpleLoader.getLoader(SimpleLoader.class),
+ });
+ }
+ }
+
+ public static final class SimpleLoader extends MultiFileLoader {
+ public SimpleLoader() {
+ super(SimpleObject.class.getName());
+ }
+ protected String displayName() {
+ return "SimpleLoader";
+ }
+ protected FileObject findPrimaryFile(FileObject fo) {
+ if (fo.hasExt("prima")) {
+ return fo;
+ }
+ return null;
+ }
+ protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException {
+ return new SimpleObject(this, primaryFile);
+ }
+ protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj, FileObject primaryFile) {
+ return new FE(obj, primaryFile);
+ }
+ protected MultiDataObject.Entry createSecondaryEntry(MultiDataObject obj, FileObject secondaryFile) {
+ return new FileEntry(obj, secondaryFile);
+ }
+ }
+
+ private static final class FE extends FileEntry {
+ public FE(MultiDataObject mo, FileObject fo) {
+ super(mo, fo);
+ }
+
+ @Override
+ public FileObject createFromTemplate(FileObject f, String name) throws IOException {
+ fail("I do not want to be called");
+ return null;
+ }
+
+
+
+ }
+
+ public static final class SimpleObject extends MultiDataObject {
+ public SimpleObject(SimpleLoader l, FileObject fo) throws DataObjectExistsException {
+ super(fo, l);
+ }
+
+ @Override
+ public String getName() {
+ return getPrimaryFile().getNameExt();
+ }
+ }
+
+ static final Logger LOG = Logger.getLogger("tst.TwoPartLoader");
+ public static final class TwoPartLoader extends MultiFileLoader {
+ static Map queried = new HashMap();
+
+ public TwoPartLoader() {
+ super(TwoPartObject.class.getName ());
+ }
+ protected String displayName() {
+ return "TwoPart";
+ }
+ protected FileObject findPrimaryFile(FileObject fo) {
+ Integer i = queried.get(fo);
+ queried.put(fo, i == null ? 1 : i + 1);
+ FileObject ret;
+
+ if (fo.hasExt("java") || fo.hasExt("form")) {
+ ret = org.openide.filesystems.FileUtil.findBrother(fo, "java");
+ } else {
+ ret = null;
+ }
+
+ LOG.fine("findPrimaryFile for " + fo + " yeilded " + ret);
+ return ret;
+ }
+ protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException {
+ LOG.info("New data object for " + primaryFile);
+ return new TwoPartObject(this, primaryFile);
+ }
+ protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj, FileObject primaryFile) {
+ LOG.fine("new primary entry " + primaryFile);
+ return new FE(obj, primaryFile);
+ }
+ protected MultiDataObject.Entry createSecondaryEntry(MultiDataObject obj, FileObject secondaryFile) {
+ LOG.fine("new snd entry: " + secondaryFile);
+ return new FE(obj, secondaryFile);
+ }
+ }
+ public static final class TwoPartObject extends MultiDataObject {
+ public TwoPartObject(TwoPartLoader l, FileObject folder) throws DataObjectExistsException {
+ super(folder, l);
+ getCookieSet().assign(FileEncodingQueryImplementation.class, eq);
+ }
+ private Charset encoding;
+ private FileEncodingQueryImplementation eq = new FileEncodingQueryImplementation() {
+
+ public Charset getEncoding(FileObject file) {
+ return encoding;
+ }
+
+ };
+ }
+
+}
diff --git a/api.templates/test/unit/src/org/netbeans/modules/templates/ScriptingCreateFromTemplateTest.java b/api.templates/test/unit/src/org/netbeans/modules/templates/ScriptingCreateFromTemplateTest.java
new file mode 100644
--- /dev/null
+++ b/api.templates/test/unit/src/org/netbeans/modules/templates/ScriptingCreateFromTemplateTest.java
@@ -0,0 +1,235 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ *
+ * The Original Software is NetBeans. The Initial Developer of the Original
+ * Software is Sun Microsystems, Inc.
+ *
+ * Portions Copyrighted 2007 Sun Microsystems, Inc.
+ */
+
+package org.netbeans.modules.templates;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.Charset;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import javax.script.ScriptEngine;
+import javax.swing.text.DefaultEditorKit;
+import javax.swing.text.Document;
+import org.netbeans.api.editor.mimelookup.MimePath;
+import org.netbeans.api.queries.FileEncodingQuery;
+import org.netbeans.junit.MockServices;
+import org.netbeans.junit.NbTestCase;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+import org.openide.loaders.DataFolder;
+import org.openide.loaders.DataObject;
+import org.openide.loaders.DataObjectExistsException;
+import org.openide.loaders.FileEntry;
+import org.openide.loaders.MultiDataObject;
+import org.openide.loaders.MultiFileLoader;
+import org.netbeans.api.editor.mimelookup.test.MockMimeLookup;
+import org.openide.loaders.CreateFromTemplateHandler;
+import org.openide.util.SharedClassObject;
+import org.openide.util.test.MockLookup;
+
+/**
+ *
+ * @author Marek Fukala
+ * @author Jaroslav Tulach
+ */
+public class ScriptingCreateFromTemplateTest extends NbTestCase {
+
+ public ScriptingCreateFromTemplateTest(String testName) {
+ super(testName);
+ }
+
+ @Override
+ protected boolean runInEQ() {
+ return true;
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ MockLookup.setInstances(SharedClassObject.findObject(SimpleLoader.class, true));
+ }
+
+ public void testCreateFromTemplateEncodingProperty() throws Exception {
+ FileObject root = FileUtil.createMemoryFileSystem().getRoot();
+ FileObject fo = FileUtil.createData(root, "simpleObject.txt");
+ OutputStream os = fo.getOutputStream();
+ os.write("print(encoding)".getBytes());
+ os.close();
+ assertEquals("content/unknown", fo.getMIMEType());
+ fo.setAttribute ("template", Boolean.TRUE);
+ assertEquals("content/unknown", fo.getMIMEType());
+ fo.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
+
+ DataObject obj = DataObject.find(fo);
+ DataFolder folder = DataFolder.findFolder(FileUtil.createFolder(root, "target"));
+
+ Map parameters = Collections.emptyMap();
+ DataObject inst = obj.createFromTemplate(folder, "complex", parameters);
+ FileObject instFO = inst.getPrimaryFile();
+
+ Charset targetEnc = FileEncodingQuery.getEncoding(instFO);
+ assertNotNull("Template encoding is null", targetEnc);
+ String instText = IndentEngineIntTest.stripNewLines(instFO.asText());
+ assertEquals("Encoding in template doesn't match", targetEnc.name(), instText);
+ }
+
+ public void testFreeFileExtension() throws Exception {
+ FileObject root = FileUtil.createMemoryFileSystem().getRoot();
+ FileObject template = FileUtil.createData(root, "simple.pl");
+ OutputStream os = template.getOutputStream();
+ ScriptEngine jsEngine = new javax.script.ScriptEngineManager().getEngineByExtension("js");
+ boolean isNashorn = (jsEngine != null && jsEngine.toString().indexOf("Nashorn") > 0);
+ if (isNashorn) {
+ // print() behaves like println() and println() does not exist:
+ os.write("print('#!/usr/bin/perl'); print('# '+license); print('# '+name+' in '+nameAndExt);".getBytes());
+ } else {
+ os.write("println('#!/usr/bin/perl'); print('# ');println(license);print('# ');print(name);print(' in ');println(nameAndExt);".getBytes());
+ }
+ os.close();
+ template.setAttribute("template", true);
+ template.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
+ Map parameters = new HashMap();
+ parameters.put("license", "GPL");
+ parameters.put(CreateFromTemplateHandler.FREE_FILE_EXTENSION, true);
+ String newLine = isNashorn ? System.getProperty("line.separator") : "\n";
+ FileObject inst = DataObject.find(template).createFromTemplate(DataFolder.findFolder(root), "nue", parameters).getPrimaryFile();
+ assertEquals("#!/usr/bin/perl"+newLine+"# GPL"+newLine+"# nue in nue.pl"+newLine, inst.asText());
+ assertEquals("nue.pl", inst.getPath());
+ /* XXX perhaps irrelevant since typical wizards disable Finish in this condition
+ inst = DataObject.find(template).createFromTemplate(DataFolder.findFolder(root), "nue", parameters).getPrimaryFile();
+ assertEquals("#!/usr/bin/perl\n# GPL\n# nue_1 in nue_1.pl\n", inst.asText());
+ assertEquals("nue_1.pl", inst.getPath());
+ */
+ inst = DataObject.find(template).createFromTemplate(DataFolder.findFolder(root), "nue.cgi", parameters).getPrimaryFile();
+ assertEquals("#!/usr/bin/perl"+newLine+"# GPL"+newLine+"# nue in nue.cgi"+newLine, inst.asText());
+ assertEquals("nue.cgi", inst.getPath());
+ /* XXX
+ inst = DataObject.find(template).createFromTemplate(DataFolder.findFolder(root), "nue.cgi", parameters).getPrimaryFile();
+ assertEquals("#!/usr/bin/perl\n# GPL\n# nue_1 in nue_1.cgi\n", inst.asText());
+ assertEquals("nue_1.cgi", inst.getPath());
+ */
+ inst = DataObject.find(template).createFromTemplate(DataFolder.findFolder(root), "explicit.pl", parameters).getPrimaryFile();
+ assertEquals("#!/usr/bin/perl"+newLine+"# GPL"+newLine+"# explicit in explicit.pl"+newLine, inst.asText());
+ assertEquals("explicit.pl", inst.getPath());
+ /* XXX
+ inst = DataObject.find(template).createFromTemplate(DataFolder.findFolder(root), "explicit.pl", parameters).getPrimaryFile();
+ assertEquals("#!/usr/bin/perl\n# GPL\n# explicit_1 in explicit_1.pl\n", inst.asText());
+ assertEquals("explicit_1.pl", inst.getPath());
+ */
+ }
+
+ //fix for this test was rolled back because of issue #120865
+ public void XtestCreateFromTemplateDocumentCreated() throws Exception {
+ FileObject root = FileUtil.createMemoryFileSystem().getRoot();
+ FileObject fo = FileUtil.createData(root, "simpleObject.txt");
+ OutputStream os = fo.getOutputStream();
+ os.write("test".getBytes());
+ os.close();
+ fo.setAttribute ("template", Boolean.TRUE);
+ fo.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
+
+ MockServices.setServices(MockMimeLookup.class);
+ MockMimeLookup.setInstances(MimePath.parse("content/unknown"), new TestEditorKit());
+
+ DataObject obj = DataObject.find(fo);
+ DataFolder folder = DataFolder.findFolder(FileUtil.createFolder(root, "target"));
+
+ assertFalse(TestEditorKit.createDefaultDocumentCalled);
+ DataObject inst = obj.createFromTemplate(folder, "test");
+ assertTrue(TestEditorKit.createDefaultDocumentCalled);
+
+ String exp = "test";
+ assertEquals(exp, inst.getPrimaryFile().asText());
+ }
+
+ public static final class SimpleLoader extends MultiFileLoader {
+ public SimpleLoader() {
+ super(SimpleObject.class.getName());
+ }
+ protected String displayName() {
+ return "SimpleLoader";
+ }
+ protected FileObject findPrimaryFile(FileObject fo) {
+ if (fo.hasExt("prima")) {
+ return fo;
+ }
+ return null;
+ }
+ protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException {
+ return new SimpleObject(this, primaryFile);
+ }
+ protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj, FileObject primaryFile) {
+ return new FE(obj, primaryFile);
+ }
+ protected MultiDataObject.Entry createSecondaryEntry(MultiDataObject obj, FileObject secondaryFile) {
+ return new FileEntry(obj, secondaryFile);
+ }
+ }
+
+ private static final class FE extends FileEntry {
+ public FE(MultiDataObject mo, FileObject fo) {
+ super(mo, fo);
+ }
+
+ @Override
+ public FileObject createFromTemplate(FileObject f, String name) throws IOException {
+ fail("I do not want to be called");
+ return null;
+ }
+ }
+
+ public static final class SimpleObject extends MultiDataObject {
+ public SimpleObject(SimpleLoader l, FileObject fo) throws DataObjectExistsException {
+ super(fo, l);
+ }
+
+ public String getName() {
+ return getPrimaryFile().getNameExt();
+ }
+ }
+
+ private static final class TestEditorKit extends DefaultEditorKit {
+
+ static boolean createDefaultDocumentCalled;
+
+ @Override
+ public Document createDefaultDocument() {
+ createDefaultDocumentCalled = true;
+ return super.createDefaultDocument();
+ }
+
+ }
+
+}
diff --git a/api.templates/test/unit/src/org/netbeans/modules/templates/utf8.xml b/api.templates/test/unit/src/org/netbeans/modules/templates/utf8.xml
new file mode 100644
--- /dev/null
+++ b/api.templates/test/unit/src/org/netbeans/modules/templates/utf8.xml
@@ -0,0 +1,4 @@
+println('');
+println('');
+println(' Žluťoučký kůň skákal přes čtvero mezí.');
+println('');
diff --git a/editor.indent/manifest.mf b/editor.indent/manifest.mf
--- a/editor.indent/manifest.mf
+++ b/editor.indent/manifest.mf
@@ -4,4 +4,5 @@
OpenIDE-Module-Layer: org/netbeans/modules/editor/indent/resources/layer.xml
AutoUpdate-Show-In-Client: false
OpenIDE-Module-Recommends: org.netbeans.modules.editor.indent.spi.CodeStylePreferences.Provider
-OpenIDE-Module-Specification-Version: 1.40
+OpenIDE-Module-Provides: org.netbeans.templates.IndentEngine
+OpenIDE-Module-Specification-Version: 1.41
diff --git a/editor.indent/nbproject/project.xml b/editor.indent/nbproject/project.xml
--- a/editor.indent/nbproject/project.xml
+++ b/editor.indent/nbproject/project.xml
@@ -50,6 +50,14 @@
org.netbeans.modules.editor.indent
+ org.netbeans.modules.editor.document
+
+
+
+ 1.3
+
+
+ org.netbeans.modules.editor.mimelookup
@@ -94,14 +102,6 @@
- org.openide.util.ui
-
-
-
- 9.3
-
-
- org.openide.util
@@ -117,6 +117,14 @@
8.0
+
+ org.openide.util.ui
+
+
+
+ 9.3
+
+
diff --git a/editor.indent/src/org/netbeans/modules/editor/indent/IndentScriptEngineHack.java b/editor.indent/src/org/netbeans/modules/editor/indent/IndentScriptEngineHack.java
new file mode 100644
--- /dev/null
+++ b/editor.indent/src/org/netbeans/modules/editor/indent/IndentScriptEngineHack.java
@@ -0,0 +1,225 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2014 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.editor.indent;
+
+import java.io.IOException;
+import java.io.Reader;
+import java.util.Collections;
+import java.util.List;
+import javax.script.AbstractScriptEngine;
+import javax.script.Bindings;
+import javax.script.ScriptContext;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineFactory;
+import javax.script.ScriptException;
+import javax.script.SimpleBindings;
+import javax.swing.text.BadLocationException;
+import javax.swing.text.Document;
+import javax.swing.text.PlainDocument;
+import javax.swing.text.Position;
+import org.netbeans.api.editor.document.LineDocumentUtils;
+import org.netbeans.modules.editor.indent.api.Reformat;
+import org.openide.util.NbBundle;
+import org.openide.util.lookup.ServiceProvider;
+
+
+/**
+ * The class implements a ScriptEngine, which is just a hacky way how to provide identation
+ * to api.templates without introducing a new SPI.
+ *
+ * @author sdedic
+ */
+public class IndentScriptEngineHack extends AbstractScriptEngine {
+ private static final String ID_INDENT_ENGINE = "org.netbeans.api.templates.IndentEngine"; // NOI18N
+
+ private IndentScriptEngineHack() {}
+
+ @Override
+ public Object eval(String text, ScriptContext context) throws ScriptException {
+ Document doc;
+ String mime = (String)context.getAttribute("mimeType"); // NOI18N
+ try {
+ doc = LineDocumentUtils.createDocument(mime);
+ } catch (IllegalArgumentException ex) {
+ // for testing: create a stupid document with a mimeType property
+ doc = new PlainDocument();
+ doc.putProperty("mimeType", mime); // NOI18N
+ }
+ Reformat reformat = Reformat.get(doc);
+ reformat.lock();
+ try {
+
+ if (text.length() > 0) {
+ try {
+ doc.insertString(0, text, null);
+ Position endPos = doc.createPosition(text.length());
+ reformat.reformat(0, endPos.getOffset());
+ int len = endPos.getOffset();
+ String reformattedText = doc.getText(0, len);
+ getContext().getWriter().write(reformattedText);
+ } catch (BadLocationException e) {
+ } catch (IOException ex) {
+ throw new ScriptException(ex);
+ }
+ }
+ } finally {
+ reformat.unlock();
+ }
+ return Boolean.TRUE;
+ }
+
+ @Override
+ public Object eval(Reader reader, ScriptContext context) throws ScriptException {
+ StringBuilder sb = new StringBuilder();
+ char[] buf = new char[1024];
+ int read;
+
+ try {
+ while ((read = reader.read(buf)) >= 0) {
+ sb.append(buf, 0, read);
+ }
+ } catch (IOException ex) {
+ throw new ScriptException(ex);
+ }
+ return eval(sb.toString());
+ }
+
+ @Override
+ public Bindings createBindings() {
+ return new SimpleBindings();
+ }
+
+ @Override
+ public ScriptEngineFactory getFactory() {
+ if (f == null) {
+ f = new Factory();
+ }
+ return f;
+ }
+
+ private Factory f;
+
+ @NbBundle.Messages({
+ "NAME_IndentScriptEngine=NetBeans indentation"
+ })
+ @ServiceProvider(service = ScriptEngineFactory.class)
+ public static class Factory implements ScriptEngineFactory {
+
+ @Override
+ public String getEngineName() {
+ return Bundle.NAME_IndentScriptEngine();
+ }
+
+ @Override
+ public String getEngineVersion() {
+ return "1.0"; // NOI18N
+ }
+
+ @Override
+ public List getExtensions() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List getMimeTypes() {
+ return Collections.emptyList();
+ }
+
+ @Override
+ public List getNames() {
+ return Collections.singletonList(ID_INDENT_ENGINE);
+ }
+
+ @Override
+ public String getLanguageName() {
+ return ""; // NOI18N
+ }
+
+ @Override
+ public String getLanguageVersion() {
+ return "-1"; // NOI18N
+ }
+
+ @Override
+ public Object getParameter(String key) {
+ switch (key) {
+ case ScriptEngine.ENGINE:
+ return getEngineName();
+ case ScriptEngine.ENGINE_VERSION:
+ return getEngineVersion();
+ case ScriptEngine.LANGUAGE:
+ return getLanguageName();
+ case ScriptEngine.LANGUAGE_VERSION:
+ return getLanguageVersion();
+ case ScriptEngine.NAME:
+ return getNames().get(0);
+ }
+ return null;
+ }
+
+ @Override
+ public String getMethodCallSyntax(String obj, String m, String... args) {
+ return null;
+ }
+
+ @Override
+ public String getOutputStatement(String toDisplay) {
+ return toDisplay;
+ }
+
+ @Override
+ public String getProgram(String... statements) {
+ StringBuilder sb = new StringBuilder();
+ for (String s : statements) {
+ sb.append(s);
+ }
+ return sb.toString();
+ }
+
+ @Override
+ public ScriptEngine getScriptEngine() {
+ return new IndentScriptEngineHack();
+ }
+
+ }
+
+}
diff --git a/java.source/nbproject/project.xml b/java.source/nbproject/project.xml
--- a/java.source/nbproject/project.xml
+++ b/java.source/nbproject/project.xml
@@ -94,6 +94,14 @@
+ org.netbeans.api.templates
+
+
+
+ 1.0
+
+
+ org.netbeans.core.multiview
diff --git a/java.source/src/org/netbeans/modules/java/IndentFileEntry.java b/java.source/src/org/netbeans/modules/java/IndentFileEntry.java
--- a/java.source/src/org/netbeans/modules/java/IndentFileEntry.java
+++ b/java.source/src/org/netbeans/modules/java/IndentFileEntry.java
@@ -115,6 +115,7 @@
/** Creates a new Java source from the template. Unlike the standard FileEntry.Format,
this indents the resulting text using an indentation engine.
*/
+ @Override
public FileObject createFromTemplate (FileObject f, String name) throws IOException {
String ext = getFile ().getExt ();
diff --git a/nbbuild/cluster.properties b/nbbuild/cluster.properties
--- a/nbbuild/cluster.properties
+++ b/nbbuild/cluster.properties
@@ -199,6 +199,7 @@
api.progress.compat8,\
api.progress.nb,\
api.search,\
+ api.templates,\
api.visual,\
applemenu,\
autoupdate.cli,\
diff --git a/nbbuild/javadoctools/links.xml b/nbbuild/javadoctools/links.xml
--- a/nbbuild/javadoctools/links.xml
+++ b/nbbuild/javadoctools/links.xml
@@ -240,3 +240,4 @@
+
diff --git a/nbbuild/javadoctools/properties.xml b/nbbuild/javadoctools/properties.xml
--- a/nbbuild/javadoctools/properties.xml
+++ b/nbbuild/javadoctools/properties.xml
@@ -239,3 +239,4 @@
+
diff --git a/nbbuild/javadoctools/replaces.xml b/nbbuild/javadoctools/replaces.xml
--- a/nbbuild/javadoctools/replaces.xml
+++ b/nbbuild/javadoctools/replaces.xml
@@ -239,3 +239,4 @@
+
diff --git a/openide.loaders/apichanges.xml b/openide.loaders/apichanges.xml
--- a/openide.loaders/apichanges.xml
+++ b/openide.loaders/apichanges.xml
@@ -109,6 +109,25 @@
+
+
+ Separate template handling
+
+
+
+
+
+ Template handling need not depend on Data System APIs, should be available
+ for clients that only know FileSystems. Relevant interfaces moved to
+ openide.filesystems.templates module; see javadoc for
+
+ FileBuilder for details.
+
+
+
+
+ Introduce targetName for templates.
diff --git a/openide.loaders/arch.xml b/openide.loaders/arch.xml
--- a/openide.loaders/arch.xml
+++ b/openide.loaders/arch.xml
@@ -80,101 +80,6 @@
A lot of usecases is described in the javadoc. Here
is the list of some faqs:
-
-
- Often many people require ability to create a "clever" template - e.g.
- write piece of simple text and at the time of its
-
- processing
-
- do some advanced changes to it using either
- scripting or templating languages.
-
-
-
- This traditionally used to be a bit complicated task, however since
- version 6.1 there are new interfaces
-
- can be registered as a services in a lookup and it is reponsible
- for handling the whole copy of the template file(s) to the destination
- folder.
- and
-
- can be registered as a services in a lookup and it is reponsible
- for providing "hints" - e.g. map mapping strings to various objects.
- and these interfaces allow anyone to extend the behaviour during
- creation of new files without writing new
- DataLoader and co.
-
-
-
- Smart Templating Quick How-To
-
-
- First of all create a file in your module layer located somewhere
- under the Templates/ folder. Make it a template by
- adding <attr name="template" boolvalue="true"/>. Associate
- this template with a scripting language, for example by
- <attr name="javax.script.ScriptEngine" stringvalue="freemarker"/>.
- Now make sure that the scripting language integration is also available
- by requesting a token in standard format, for freemarker just put
- OpenIDE-Module-Needs: javax.script.ScriptEngine.freemarker
- in your manifest. This tells the NetBeans module system that a
- module providing integration with such scripting engine has to be
- enabled. Now you can use regular script language tags inside of
- your template file. When you write your instantiate
- method in your wizard, you can create a Map<String,Object> and
- fill it with parameters collected from your wizard and then pass it
- to
-
- createFromTemplate(targetFolder, targetName, mapWithParameters)
- . This will invoke the scripting language and make the
- mapWithParameters values available to it. Beyond this
- there is few standard parameters predefined including name, user, date, time, etc.
- and also additional parameters are collected from all registered
- CreateFromTemplateAttributesProviders.
-
-
-
- Moreover there is a built in support for scripting languages in
- the standard NetBeans IDE. If a template is annotated with
-
- a property that can be associated to templates that either should
- return real instance of ScriptEngine interface or
- a String name of the engine that is then used to
- search for it in the javax.script.ScriptEngineManager.
- Usually the freemarker engine is the one that is
- supported by the NetBeans IDE - if your module wants to use it
- then include a token dependency OpenIDE-Module-Needs: javax.script.ScriptEngine.freemarker
- in your manifest file (also accessible through project customizer GUI)
- to indicate to the system that you need it.
-
- then the scripting engine is then used to process the template and
- generate the output file. While running the engine one can rely
- on few predefined properties:
-
-
-
-
contains the name of the DataObject that is being created
-
contains the name the user
-
contains the name and extension of the file that is being created
-
contains String representing the current day like 23. 3. 2007
-
contains String the current time like 17:18:30
-
contains java.util.Date representing current data and time like
-
contains String the file encoding of the template instance
-
-
-
- Other properties can indeed be provided by
- CreateFromTemplateAttributesProviders.
- After processing, the output is also sent to appropriate
- org.openide.text.IndentEngine associated
- with the mime type of the template, for formating.
-
-
-
The actions that the default folder loader shows in its popup menu are read from
diff --git a/openide.loaders/manifest.mf b/openide.loaders/manifest.mf
--- a/openide.loaders/manifest.mf
+++ b/openide.loaders/manifest.mf
@@ -1,6 +1,6 @@
Manifest-Version: 1.0
OpenIDE-Module: org.openide.loaders
-OpenIDE-Module-Specification-Version: 7.60
+OpenIDE-Module-Specification-Version: 7.61
OpenIDE-Module-Localizing-Bundle: org/openide/loaders/Bundle.properties
OpenIDE-Module-Provides: org.netbeans.modules.templates.v1_0
OpenIDE-Module-Layer: org/netbeans/modules/openide/loaders/layer.xml
diff --git a/openide.loaders/module-auto-deps.xml b/openide.loaders/module-auto-deps.xml
--- a/openide.loaders/module-auto-deps.xml
+++ b/openide.loaders/module-auto-deps.xml
@@ -60,5 +60,18 @@
+
+ No need for separate templates API. Merged into org.openide.loaders
+
+
+
+
+
+
+
+
+
+
+
diff --git a/openide.loaders/nbproject/project.xml b/openide.loaders/nbproject/project.xml
--- a/openide.loaders/nbproject/project.xml
+++ b/openide.loaders/nbproject/project.xml
@@ -142,6 +142,14 @@
+ org.netbeans.api.templates
+
+
+
+ 1.0
+
+
+ org.openide.modules
diff --git a/openide.loaders/src/org/netbeans/api/templates/TemplateRegistration.java b/openide.loaders/src/org/netbeans/api/templates/TemplateRegistration.java
deleted file mode 100644
--- a/openide.loaders/src/org/netbeans/api/templates/TemplateRegistration.java
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
- *
- * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
- * Other names may be trademarks of their respective owners.
- *
- * The contents of this file are subject to the terms of either the GNU
- * General Public License Version 2 only ("GPL") or the Common Development and
- * Distribution License("CDDL") (collectively, the "License"). You may not use
- * this file except in compliance with the License. You can obtain a copy of
- * the License at http://www.netbeans.org/cddl-gplv2.html or
- * nbbuild/licenses/CDDL-GPL-2-CP. See the License for the specific language
- * governing permissions and limitations under the License. When distributing
- * the software, include this License Header Notice in each file and include
- * the License file at nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided by
- * Oracle in the GPL Version 2 section of the License file that accompanied
- * this code. If applicable, add the following below the License Header, with
- * the fields enclosed by brackets [] replaced by your own identifying
- * information: "Portions Copyrighted [year] [name of copyright owner]"
- *
- * If you wish your version of this file to be governed by only the CDDL or
- * only the GPL Version 2, indicate your decision by adding "[Contributor]
- * elects to include this software in this distribution under the [CDDL or GPL
- * Version 2] license." If you do not indicate a single choice of license, a
- * recipient has the option to distribute your version of this file under
- * either the CDDL, the GPL Version 2 or to extend the choice of license to its
- * licensees as provided above. However, if you add GPL Version 2 code and
- * therefore, elected the GPL Version 2 license, then the option applies only
- * if the new code is made subject to such option by the copyright holder.
- *
- * Contributor(s):
- *
- * Portions Copyrighted 2011 Sun Microsystems, Inc.
- */
-
-package org.netbeans.api.templates;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import javax.script.ScriptEngineFactory;
-import org.openide.WizardDescriptor.InstantiatingIterator;
-import org.openide.loaders.TemplateWizard;
-
-/**
- * Registers a template the user can select.
- * May be placed on a class (with a default constructor) or static method (with no arguments)
- * to register an {@link InstantiatingIterator} for a custom template;
- * or on a package to register a plain-file template with no custom behavior.
- * @since 7.29
- * @see TemplateWizard
- * @see TemplateRegistrations
- * @see org.netbeans.spi.project.ui.templates.support
- */
-@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PACKAGE})
-@Retention(RetentionPolicy.SOURCE)
-public @interface TemplateRegistration {
-
- /**
- * Subfolder in which to place the template, such as {@code Other} or {@code Project/Standard}.
- */
- String folder();
-
- /**
- * Optional position within {@link #folder}.
- */
- int position() default Integer.MAX_VALUE;
-
- /**
- * Special file basename to use rather than inferring one from the declaring element,
- * when {@link #content} is empty.
- * Useful for pure templates referenced from {@code PrivilegedTemplates}.
- */
- String id() default "";
-
- /**
- * File contents, as resources relative to the package of this declaration.
- * A nonempty list is mandatory for a template registered on a package.
- * For a template with a custom iterator, the content may be omitted, though it may still be specified.
- *
Normally only a single file is specified, but for a multifile data object, list the primary entry first.
- *
The file basenames (incl. extension) of the actual template files (as in {@link TemplateWizard#getTemplate})
- * will be taken from the basename of the content resources, though a {@code .template} suffix
- * may be appended to prevent template resources in a source project from being misinterpreted.
- * For a "pure" custom iterator with no specified content, the template basename
- * defaults to the FQN of the class or method defining it but with {@code -} for {@code .} characters,
- * e.g. {@code pkg-Class-method}, but may be overridden with {@link #id}.
- *
Example usage for a simple, single-file template (with or without custom iterator):
- *
- */
- String[] content() default {};
-
- /**
- * Localized label for the template.
- * Mandatory unless {@link #content} is specified, in which case it would be defaulted by the data node.
- * May use the usual {@code #key} syntax.
- */
- String displayName() default "";
-
- /**
- * Icon to use for the template.
- * Should be an absolute resource path (no initial slash).
- * Mandatory unless {@link #content} is specified, in which case it would be defaulted by the data node.
- */
- String iconBase() default "";
-
- /**
- * Optional but recommended relative resource path to an HTML description of the template.
- * @see TemplateWizard#getDescription
- */
- String description() default "";
-
- /**
- * Optional name of a script engine to use when processing file content, such as {@code freemarker}.
- * @see ScriptEngineFactory#getNames
- */
- String scriptEngine() default "";
-
- /**
- * Optional list of categories interpreted by the project system.
- */
- String[] category() default {};
-
- /**
- * Set to false if the template can be instantiated without a project.
- * @since 7.46
- */
- boolean requireProject() default true;
-
- /**
- * Default (pre-filled) target name for the template, without extension. May
- * use the usual {@code #key} syntax for localization or branding.
- *
- * @since 7.56
- */
- String targetName() default "";
-}
diff --git a/openide.loaders/src/org/netbeans/api/templates/TemplateRegistrations.java b/openide.loaders/src/org/netbeans/api/templates/TemplateRegistrations.java
deleted file mode 100644
--- a/openide.loaders/src/org/netbeans/api/templates/TemplateRegistrations.java
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2011 Oracle and/or its affiliates. All rights reserved.
- *
- * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
- * Other names may be trademarks of their respective owners.
- *
- * The contents of this file are subject to the terms of either the GNU
- * General Public License Version 2 only ("GPL") or the Common Development and
- * Distribution License("CDDL") (collectively, the "License"). You may not use
- * this file except in compliance with the License. You can obtain a copy of
- * the License at http://www.netbeans.org/cddl-gplv2.html or
- * nbbuild/licenses/CDDL-GPL-2-CP. See the License for the specific language
- * governing permissions and limitations under the License. When distributing
- * the software, include this License Header Notice in each file and include
- * the License file at nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided by
- * Oracle in the GPL Version 2 section of the License file that accompanied
- * this code. If applicable, add the following below the License Header, with
- * the fields enclosed by brackets [] replaced by your own identifying
- * information: "Portions Copyrighted [year] [name of copyright owner]"
- *
- * If you wish your version of this file to be governed by only the CDDL or
- * only the GPL Version 2, indicate your decision by adding "[Contributor]
- * elects to include this software in this distribution under the [CDDL or GPL
- * Version 2] license." If you do not indicate a single choice of license, a
- * recipient has the option to distribute your version of this file under
- * either the CDDL, the GPL Version 2 or to extend the choice of license to its
- * licensees as provided above. However, if you add GPL Version 2 code and
- * therefore, elected the GPL Version 2 license, then the option applies only
- * if the new code is made subject to such option by the copyright holder.
- *
- * Contributor(s):
- *
- * Portions Copyrighted 2011 Sun Microsystems, Inc.
- */
-
-package org.netbeans.api.templates;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * May be used to register multiple plain-file {@link TemplateRegistration}s.
- * Use on a package for simple templates, or on an iterator for multiple variants of a template
- * with different {@link TemplateRegistration#content}.
- * @since 7.29
- */
-@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PACKAGE})
-@Retention(RetentionPolicy.SOURCE)
-public @interface TemplateRegistrations {
- TemplateRegistration[] value();
-}
diff --git a/openide.loaders/src/org/netbeans/modules/templates/DesktopTemplateAttributes.java b/openide.loaders/src/org/netbeans/modules/templates/DesktopTemplateAttributes.java
new file mode 100644
--- /dev/null
+++ b/openide.loaders/src/org/netbeans/modules/templates/DesktopTemplateAttributes.java
@@ -0,0 +1,76 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2014 Sun Microsystems, Inc.
+ */
+package org.netbeans.modules.templates;
+
+import java.text.DateFormat;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import org.netbeans.api.templates.CreateDescriptor;
+import org.netbeans.api.templates.CreateFromTemplateAttributes;
+import org.openide.util.lookup.ServiceProvider;
+
+/**
+ * Compatible implementation for desktop applications. Provides username and
+ * date/time format based on JRE properties/defaults.
+ *
+ * @author sdedic
+ */
+@ServiceProvider(service = CreateFromTemplateAttributes.class, position = Integer.MIN_VALUE)
+public class DesktopTemplateAttributes implements CreateFromTemplateAttributes {
+ @Override
+ public Map attributesFor(CreateDescriptor desc) {
+ Map vals = new HashMap();
+ Date d = new Date();
+ vals.put("user", // NOI18N
+ System.getProperty("user.name") // NOI18N
+ );
+ vals.put("date", // NOI18N
+ DateFormat.getDateInstance(DateFormat.DEFAULT, desc.getLocale()).format(d)
+ );
+ vals.put("time", // NOI18N
+ DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, desc.getLocale()).format(d)
+ );
+
+ return vals;
+ }
+}
diff --git a/openide.loaders/src/org/netbeans/modules/templates/ScriptingCreateFromTemplateHandler.java b/openide.loaders/src/org/netbeans/modules/templates/ScriptingCreateFromTemplateHandler.java
deleted file mode 100644
--- a/openide.loaders/src/org/netbeans/modules/templates/ScriptingCreateFromTemplateHandler.java
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
- *
- * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
- * Other names may be trademarks of their respective owners.
- *
- * The contents of this file are subject to the terms of either the GNU
- * General Public License Version 2 only ("GPL") or the Common
- * Development and Distribution License("CDDL") (collectively, the
- * "License"). You may not use this file except in compliance with the
- * License. You can obtain a copy of the License at
- * http://www.netbeans.org/cddl-gplv2.html
- * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
- * specific language governing permissions and limitations under the
- * License. When distributing the software, include this License Header
- * Notice in each file and include the License file at
- * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the GPL Version 2 section of the License file that
- * accompanied this code. If applicable, add the following below the
- * License Header, with the fields enclosed by brackets [] replaced by
- * your own identifying information:
- * "Portions Copyrighted [year] [name of copyright owner]"
- *
- * Contributor(s):
- *
- * The Original Software is NetBeans. The Initial Developer of the Original
- * Software is Sun Microsystems, Inc.
- *
- * Portions Copyrighted 2007 Sun Microsystems, Inc.
- */
-
-package org.netbeans.modules.templates;
-
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.io.Reader;
-import java.io.Writer;
-import java.nio.charset.Charset;
-import java.util.Map;
-import javax.script.Bindings;
-import javax.script.ScriptContext;
-import javax.script.ScriptEngine;
-import javax.script.ScriptEngineManager;
-import javax.script.ScriptException;
-import javax.swing.text.PlainDocument;
-import org.netbeans.api.queries.FileEncodingQuery;
-import org.openide.filesystems.FileObject;
-import org.openide.filesystems.FileUtil;
-import org.openide.loaders.CreateFromTemplateHandler;
-import org.openide.text.IndentEngine;
-import org.openide.util.Lookup;
-import org.openide.util.lookup.ServiceProvider;
-
-
-/** Processes templates that have associated attribute
-* with name of the scripting engine.
-*
-* @author Jaroslav Tulach
-*/
-@ServiceProvider(service=CreateFromTemplateHandler.class)
-public class ScriptingCreateFromTemplateHandler extends CreateFromTemplateHandler {
-
- public static final String SCRIPT_ENGINE_ATTR = "javax.script.ScriptEngine";
-
- private static ScriptEngineManager manager;
-
- private static final String ENCODING_PROPERTY_NAME = "encoding"; //NOI18N
-
- @Override
- protected boolean accept(FileObject orig) {
- return engine(orig) != null;
- }
-
- @Override
- protected FileObject createFromTemplate(FileObject template, FileObject f,
- String name,
- Map values) throws IOException {
- boolean noExt = Boolean.TRUE.equals(values.get(FREE_FILE_EXTENSION)) && name.indexOf('.') != -1;
-
- String extWithDot;
- if (noExt) {
- extWithDot = null;
- } else {
- extWithDot = '.' + template.getExt();
- if (name.endsWith(extWithDot)) { // Test whether the extension happens to be there already
- // And remove it if yes, it will be appended to the unique name.
- name = name.substring(0, name.length() - extWithDot.length());
- }
- }
-
- String nameUniq = FileUtil.findFreeFileName(f, name, noExt ? null : template.getExt());
- FileObject output = FileUtil.createData(f, noExt ? nameUniq : nameUniq + extWithDot);
- Charset targetEnc = FileEncodingQuery.getEncoding(output);
- Charset sourceEnc = FileEncodingQuery.getEncoding(template);
-
- ScriptEngine eng = engine(template);
- Bindings bind = eng.getContext().getBindings(ScriptContext.ENGINE_SCOPE);
- bind.putAll(values);
-
- if(!values.containsKey(ENCODING_PROPERTY_NAME)) {
- bind.put(ENCODING_PROPERTY_NAME, targetEnc.name());
- }
-
- Writer w = null;
- Reader is = null;
- try {
- w = new OutputStreamWriter(output.getOutputStream(), targetEnc);
-
- IndentEngine format = IndentEngine.find(template.getMIMEType());
- if (format != null) {
- PlainDocument doc = new PlainDocument();
- doc.putProperty(PlainDocument.StreamDescriptionProperty, template);
- w = format.createWriter(doc, 0, w);
- }
-
-
- eng.getContext().setWriter(new PrintWriter(w));
- //eng.getContext().setBindings(bind, ScriptContext.ENGINE_SCOPE);
- eng.getContext().setAttribute(FileObject.class.getName(), template, ScriptContext.ENGINE_SCOPE);
- eng.getContext().setAttribute(ScriptEngine.FILENAME, template.getNameExt(), ScriptContext.ENGINE_SCOPE);
- is = new InputStreamReader(template.getInputStream(), sourceEnc);
- eng.eval(is);
- }catch (ScriptException ex) {
- IOException io = new IOException(ex.getMessage(), ex);
- throw io;
- } finally {
- if (w != null) w.close();
- if (is != null) is.close();
- }
- return output;
- }
-
- private static ScriptEngine engine(FileObject fo) {
- Object obj = fo.getAttribute(SCRIPT_ENGINE_ATTR); // NOI18N
- if (obj instanceof ScriptEngine) {
- return (ScriptEngine)obj;
- }
- if (obj instanceof String) {
- synchronized (ScriptingCreateFromTemplateHandler.class) {
- if (manager == null) {
- ClassLoader loader = Lookup.getDefault().lookup(ClassLoader.class);
- manager = new ScriptEngineManager(loader != null ? loader : Thread.currentThread().getContextClassLoader());
- }
- }
- return manager.getEngineByName((String) obj);
- }
- return null;
- }
-}
diff --git a/openide.loaders/src/org/netbeans/modules/templates/TemplateProcessor.java b/openide.loaders/src/org/netbeans/modules/templates/TemplateProcessor.java
--- a/openide.loaders/src/org/netbeans/modules/templates/TemplateProcessor.java
+++ b/openide.loaders/src/org/netbeans/modules/templates/TemplateProcessor.java
@@ -38,8 +38,6 @@
package org.netbeans.modules.templates;
-import java.net.URI;
-import java.net.URISyntaxException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
@@ -58,6 +56,14 @@
import org.openide.filesystems.annotations.LayerGeneratingProcessor;
import org.openide.util.lookup.ServiceProvider;
+/**
+ * The processor was split into two parts. The part which defines how the template
+ * annotation fields will be translated into the XML layer is defined in {@code openide.filesystems.templates}
+ * module. This Processor implementation binds the template to a Wizard Iterator, if the annotation is on
+ * an executable method.
+ *
+ * @author sdedic
+ */
@ServiceProvider(service=Processor.class)
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class TemplateProcessor extends LayerGeneratingProcessor {
@@ -86,7 +92,7 @@
process(e, t);
}
}
- return true;
+ return false;
}
private void process(Element e, TemplateRegistration t) throws LayerGenerationException {
@@ -110,61 +116,13 @@
}
String folder = "Templates/" + t.folder() + '/';
LayerBuilder.File f = builder.file(folder + basename);
- f.boolvalue("template", true);
- f.position(t.position());
- if (!t.displayName().isEmpty()) {
- f.bundlevalue("displayName", t.displayName());
- }
- if (!t.iconBase().isEmpty()) {
- builder.validateResource(t.iconBase(), e, t, "iconBase", true);
- f.stringvalue("iconBase", t.iconBase());
- } else if (t.content().length == 0) {
- throw new LayerGenerationException("Must specify iconBase if content is not specified", e, processingEnv, t);
- }
- if (!t.description().isEmpty()) {
- f.urlvalue("instantiatingWizardURL", contentURI(e, t.description(), builder, t, "description"));
- }
if (e.getKind() != ElementKind.PACKAGE) {
f.instanceAttribute("instantiatingIterator", InstantiatingIterator.class);
}
- if (t.content().length > 0) {
- f.url(contentURI(e, t.content()[0], builder, t, "content").toString());
- for (int i = 1; i < t.content().length; i++) {
- builder.file(folder + basename(t.content()[i])).url(contentURI(e, t.content()[i], builder, t, "content").toString()).position(0).write();
- }
- }
- if (!t.scriptEngine().isEmpty()) {
- f.stringvalue(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, t.scriptEngine());
- }
- if (t.category().length > 0) {
- StringBuilder sb = new StringBuilder();
- for (String c : t.category()) {
- if (sb.length() > 0) {
- sb.append(',');
- }
- sb.append(c);
- }
- f.stringvalue("templateCategory", sb.toString());
- }
- f.boolvalue("requireProject", t.requireProject());
- if (!t.targetName().trim().isEmpty()) {
- f.bundlevalue("targetName", t.targetName()); //NOI18N
- }
f.write();
}
private static String basename(String relativeResource) {
return relativeResource.replaceFirst(".+/", "").replaceFirst("[.]template$", "");
}
-
- private URI contentURI(Element e, String relativePath, LayerBuilder builder, TemplateRegistration t, String annotationMethod) throws LayerGenerationException {
- String path = LayerBuilder.absolutizeResource(e, relativePath);
- builder.validateResource(path, e, t, annotationMethod, false);
- try {
- return new URI("nbresloc", "/" + path, null).normalize();
- } catch (URISyntaxException x) {
- throw new LayerGenerationException("could not translate " + path, e, processingEnv, t);
- }
- }
-
}
diff --git a/openide.loaders/src/org/openide/actions/SaveAsTemplateAction.java b/openide.loaders/src/org/openide/actions/SaveAsTemplateAction.java
--- a/openide.loaders/src/org/openide/actions/SaveAsTemplateAction.java
+++ b/openide.loaders/src/org/openide/actions/SaveAsTemplateAction.java
@@ -50,7 +50,6 @@
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
-import org.netbeans.modules.templates.ScriptingCreateFromTemplateHandler;
import org.openide.cookies.SaveCookie;
import org.openide.filesystems.FileObject;
import org.openide.loaders.*;
@@ -136,6 +135,8 @@
protected boolean asynchronous() {
return false;
}
+
+ static final String SCRIPT_ENGINE_ATTR = "javax.script.ScriptEngine"; // NOI18N
/** Performs the work of creating a new template */
private void createNewTemplate(DataObject source,
@@ -156,7 +157,7 @@
newTemplate.setTemplate(true);
if (templateSample == null) {
// a fallback if no template sample found
- newTemplate.getPrimaryFile().setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "freemarker"); // NOI18N
+ newTemplate.getPrimaryFile().setAttribute(SCRIPT_ENGINE_ATTR, "freemarker"); // NOI18N
} else {
setTemplateAttributes (newTemplate.getPrimaryFile (), getAttributes (templateSample.getPrimaryFile ()));
}
diff --git a/openide.loaders/src/org/openide/loaders/CreateFromTemplateAttributesProvider.java b/openide.loaders/src/org/openide/loaders/CreateFromTemplateAttributesProvider.java
--- a/openide.loaders/src/org/openide/loaders/CreateFromTemplateAttributesProvider.java
+++ b/openide.loaders/src/org/openide/loaders/CreateFromTemplateAttributesProvider.java
@@ -41,9 +41,18 @@
* and allows anyone provide additional parameters to each {@link CreateFromTemplateHandler}s
* when a template is instantiating.
* Read more in the howto document.
+ *
+ * Since templating system need not to depend on Data Systems APIs, the relevant interfaces
+ * were moved to the {@code openide.filesystems.templates} module. This interface has been kept
+ * for backward compatibility and DataSystems provide a compatibility bridge, which allows
+ * old providers to participate. Module writers are encouraged to implement
+ * {@link org.netbeans.api.templates.CreateFromTemplateAttributes}
+ * instead.
*
* @author Jaroslav Tulach
* @since 6.3
+ * @since deprecated from 7.59
+ * @deprecated Use {@link CreateFromTemplateAttributes} in {@code openide.filesystems.templates} instead.
*/
public interface CreateFromTemplateAttributesProvider {
/** Called when a template is about to be instantiated to provide additional
diff --git a/openide.loaders/src/org/openide/loaders/CreateFromTemplateHandler.java b/openide.loaders/src/org/openide/loaders/CreateFromTemplateHandler.java
--- a/openide.loaders/src/org/openide/loaders/CreateFromTemplateHandler.java
+++ b/openide.loaders/src/org/openide/loaders/CreateFromTemplateHandler.java
@@ -35,7 +35,10 @@
package org.openide.loaders;
import java.io.IOException;
+import java.util.Collections;
+import java.util.List;
import java.util.Map;
+import org.netbeans.api.templates.CreateDescriptor;
import org.openide.filesystems.FileObject;
/** This is an interface for smart templating that allows
@@ -43,11 +46,34 @@
* and handle them themselves. The NetBeans IDE provides default
* implementation that allows use of Freemarker templating engine.
* Read more in the howto document.
- *
+ *
+ * This SPI is now deprecated and serves just a backward compatilibity SPI adapter
+ * which allows the template API to work with legacy handlers. The templating SPI is delegated
+ * to the original handler methods.
+ *
* @author Jaroslav Tulach
* @since 6.1
+ * @deprecated in 7.59. Use {@link org.netbeans.api.templates.CreateFromTemplateHandler} instead.
*/
-public abstract class CreateFromTemplateHandler {
+public abstract class CreateFromTemplateHandler extends org.netbeans.api.templates.CreateFromTemplateHandler {
+
+ @Override
+ public boolean accept(CreateDescriptor desc) {
+ return accept(desc.getTemplate());
+ }
+
+ @Override
+ protected List createFromTemplate(CreateDescriptor desc) throws IOException {
+ return Collections.singletonList(
+ createFromTemplate(
+ desc.getTemplate(),
+ desc.getTarget(),
+ desc.getName(),
+ desc.getParameters()
+ )
+ );
+ }
+
/** Method that allows a handler to reject a file. If all handlers
* reject a file, regular processing defined in {@link DataObject#handleCreateFromTemplate}
* is going to take place.
diff --git a/openide.loaders/src/org/openide/loaders/DataObject.java b/openide.loaders/src/org/openide/loaders/DataObject.java
--- a/openide.loaders/src/org/openide/loaders/DataObject.java
+++ b/openide.loaders/src/org/openide/loaders/DataObject.java
@@ -1601,6 +1601,19 @@
}
}
+ public static Map getCallParameters(String name) {
+ CreateAction c = CURRENT.get();
+ if (c == null || c.param == null) {
+ return Collections.emptyMap();
+ }
+ return Collections.unmodifiableMap(c.param);
+ }
+
+ static String getOrigName() {
+ CreateAction c = CURRENT.get();
+ return c == null ? null : c.name;
+ }
+
public static Map findParameters(String name) {
CreateAction c = CURRENT.get();
if (c == null) {
diff --git a/openide.loaders/src/org/openide/loaders/FileEntry.java b/openide.loaders/src/org/openide/loaders/FileEntry.java
--- a/openide.loaders/src/org/openide/loaders/FileEntry.java
+++ b/openide.loaders/src/org/openide/loaders/FileEntry.java
@@ -45,8 +45,9 @@
package org.openide.loaders;
import java.io.*;
+import java.util.List;
+import org.netbeans.api.templates.FileBuilder;
import org.openide.filesystems.*;
-import org.openide.util.Lookup;
import org.openide.util.NbBundle;
/** Entry that works with plain files. Copies, moves,
@@ -149,32 +150,11 @@
* @param f the folder to create instance in
* @param name name of the file or null if it should be choosen automaticly
*/
+ @Override
public FileObject createFromTemplate (FileObject f, String name) throws IOException {
- if (name == null) {
- name = FileUtil.findFreeFileName(
- f,
- getFile ().getName (), getFile ().getExt ()
- );
- }
-
-
- FileObject fo = null;
- for (CreateFromTemplateHandler h : Lookup.getDefault().lookupAll(CreateFromTemplateHandler.class)) {
- if (h.accept(getFile())) {
- fo = h.createFromTemplate(getFile(), f, name,
- DataObject.CreateAction.enhanceParameters(
- DataObject.CreateAction.findParameters(name),
- name, getFile().getExt()));
- assert fo != null;
- break;
- }
- }
-
- if (fo == null) {
- fo = getFile().copy (f, name, getFile().getExt ());
- }
-
-
+ FileObject fo = FileBuilder.createFromTemplate(getFile(), f, name,
+ DataObject.CreateAction.getCallParameters(name),
+ FileBuilder.Mode.COPY);
// unmark template state
DataObject.setTemplate (fo, false);
@@ -204,65 +184,21 @@
* @param f the folder to create instance in
* @param name name of the file or null if it should be choosen automaticly
*/
+ @Override
+ @SuppressWarnings("AssignmentToMethodParameter")
public FileObject createFromTemplate (FileObject f, String name) throws IOException {
String ext = getFile ().getExt ();
-
if (name == null) {
name = FileUtil.findFreeFileName(
f,
getFile ().getName (), ext
);
}
-
- FileObject fo = null;
- for (CreateFromTemplateHandler h : Lookup.getDefault().lookupAll(CreateFromTemplateHandler.class)) {
- if (h.accept(getFile())) {
- fo = h.createFromTemplate(
- getFile(), f, name,
- DataObject.CreateAction.enhanceParameters(
- DataObject.CreateAction.findParameters(name),
- name, getFile().getExt()));
- assert fo != null;
- break;
- }
- }
-
- if (fo != null) {
- // unmark template state
- DataObject.setTemplate (fo, false);
- return fo;
- }
-
- fo = f.createData (name, ext);
-
java.text.Format frm = createFormat (f, name, ext);
-
- BufferedReader r = new BufferedReader (new InputStreamReader (getFile ().getInputStream ()));
- try {
- FileLock lock = fo.lock ();
- try {
- BufferedWriter w = new BufferedWriter (new OutputStreamWriter (fo.getOutputStream (lock)));
-
- try {
- String current;
- while ((current = r.readLine ()) != null) {
- w.write (frm.format (current));
- // Cf. #7061.
- w.newLine ();
- }
- } finally {
- w.close ();
- }
- } finally {
- lock.releaseLock ();
- }
- } finally {
- r.close ();
- }
-
- // copy attributes
- FileUtil.copyAttributes (getFile (), fo);
-
+ List fos = new FileBuilder(getFile(), f).name(name).
+ withParameters(DataObject.CreateAction.getCallParameters(name)).
+ useFormat(frm).build();
+ FileObject fo = fos.get(0);
// unmark template state
DataObject.setTemplate (fo, false);
diff --git a/openide.loaders/src/org/openide/loaders/FileTemplateHandlerBridge.java b/openide.loaders/src/org/openide/loaders/FileTemplateHandlerBridge.java
new file mode 100644
--- /dev/null
+++ b/openide.loaders/src/org/openide/loaders/FileTemplateHandlerBridge.java
@@ -0,0 +1,104 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2014 Oracle and/or its affiliates. All rights reserved.
+ *
+ * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
+ * Other names may be trademarks of their respective owners.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common
+ * Development and Distribution License("CDDL") (collectively, the
+ * "License"). You may not use this file except in compliance with the
+ * License. You can obtain a copy of the License at
+ * http://www.netbeans.org/cddl-gplv2.html
+ * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
+ * specific language governing permissions and limitations under the
+ * License. When distributing the software, include this License Header
+ * Notice in each file and include the License file at
+ * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the GPL Version 2 section of the License file that
+ * accompanied this code. If applicable, add the following below the
+ * License Header, with the fields enclosed by brackets [] replaced by
+ * your own identifying information:
+ * "Portions Copyrighted [year] [name of copyright owner]"
+ *
+ * If you wish your version of this file to be governed by only the CDDL
+ * or only the GPL Version 2, indicate your decision by adding
+ * "[Contributor] elects to include this software in this distribution
+ * under the [CDDL or GPL Version 2] license." If you do not indicate a
+ * single choice of license, a recipient has the option to distribute
+ * your version of this file under either the CDDL, the GPL Version 2 or
+ * to extend the choice of license to its licensees as provided above.
+ * However, if you add GPL Version 2 code and therefore, elected the GPL
+ * Version 2 license, then the option applies only if the new code is
+ * made subject to such option by the copyright holder.
+ *
+ * Contributor(s):
+ *
+ * Portions Copyrighted 2014 Sun Microsystems, Inc.
+ */
+package org.openide.loaders;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import org.netbeans.api.templates.CreateDescriptor;
+import org.openide.filesystems.FileObject;
+import org.netbeans.api.templates.CreateFromTemplateAttributes;
+import org.openide.util.Exceptions;
+import org.openide.util.Lookup;
+import org.openide.util.lookup.ServiceProvider;
+
+/**
+ * Bridges loader-based handler registration to the fileobject-based one. Provides
+ * compatibility with NB <= 8.0.1. New clients are encouraged to use the new
+ * {@link CreateFromTemplateAttributes} interface directly.
+ *
+ * @author sdedic
+ */
+@ServiceProvider(service = CreateFromTemplateAttributes.class, position = Integer.MIN_VALUE)
+public class FileTemplateHandlerBridge implements CreateFromTemplateAttributes {
+ private Lookup.Result providers;
+
+ public FileTemplateHandlerBridge() {
+ providers = Lookup.getDefault().lookupResult(CreateFromTemplateAttributesProvider.class);
+ }
+
+ @Override
+ public Map attributesFor(CreateDescriptor desc) {
+ FileObject template = desc.getTemplate();
+ FileObject target = desc.getTarget();
+ Collection extends CreateFromTemplateAttributesProvider> c = providers.allInstances();
+ if (c.isEmpty()) {
+ return Collections.emptyMap();
+ }
+ DataObject d;
+ DataFolder fld;
+
+ try {
+ d = DataObject.find(template);
+ fld = DataFolder.findFolder(target);
+ } catch (DataObjectNotFoundException ex) {
+ // ???
+ Exceptions.printStackTrace(ex);
+ return Collections.emptyMap();
+ }
+ HashMap all = new HashMap();
+ for (CreateFromTemplateAttributesProvider p : c) {
+ // must use getName, since some features may rely on that null propagates to the Provider
+ // if the initiator does not specify a name.
+ Map map = p.attributesFor(d, fld, DataObject.CreateAction.getOrigName());
+ if (map != null) {
+ for (Map.Entry e : map.entrySet()) {
+ all.put(e.getKey(), e.getValue());
+ }
+ }
+ }
+
+ return all;
+ }
+
+}
diff --git a/openide.loaders/src/org/openide/loaders/MultiDataObject.java b/openide.loaders/src/org/openide/loaders/MultiDataObject.java
--- a/openide.loaders/src/org/openide/loaders/MultiDataObject.java
+++ b/openide.loaders/src/org/openide/loaders/MultiDataObject.java
@@ -49,24 +49,18 @@
import java.beans.PropertyVetoException;
import java.io.*;
import java.lang.ref.WeakReference;
-import java.lang.reflect.Method;
import java.util.*;
-import java.util.concurrent.Callable;
import java.util.logging.*;
import javax.swing.event.*;
import org.netbeans.api.actions.Editable;
import org.netbeans.api.actions.Openable;
+import org.netbeans.api.templates.FileBuilder;
import org.openide.cookies.CloseCookie;
import org.openide.cookies.EditorCookie;
import org.openide.cookies.LineCookie;
-import org.openide.cookies.PrintCookie;
import org.openide.filesystems.*;
import org.openide.nodes.*;
-import org.openide.nodes.Node.Cookie;
import org.openide.text.CloneableEditor;
-import org.openide.text.CloneableEditorSupport;
-import org.openide.text.CloneableEditorSupport.Pane;
-import org.openide.text.DataEditorSupport;
import org.openide.util.*;
/** Provides support for handling of data objects with multiple files.
@@ -876,21 +870,9 @@
}
FileObject pf = null;
- Map params = null;
- for (CreateFromTemplateHandler h : Lookup.getDefault().lookupAll(CreateFromTemplateHandler.class)) {
- FileObject current = getPrimaryEntry().getFile();
- if (h.accept(current)) {
- if (params == null) {
- params = DataObject.CreateAction.findParameters(name);
- }
- pf = h.createFromTemplate(current, df.getPrimaryFile(), name,
- DataObject.CreateAction.enhanceParameters(params, name, current.getExt())
- );
- assert pf != null;
- break;
- }
- }
- if (params == null) {
+ Map params = CreateAction.getCallParameters(name);
+ pf = FileBuilder.createFromTemplate(getPrimaryFile(), df.getPrimaryFile(), name, params, FileBuilder.Mode.FAIL);
+ if (pf == null) {
// do the regular creation
pf = getPrimaryEntry().createFromTemplate (df.getPrimaryFile (), name);
}
@@ -899,20 +881,11 @@
Iterator it = secondaryEntries().iterator();
NEXT_ENTRY: while (it.hasNext ()) {
Entry entry = it.next();
- for (CreateFromTemplateHandler h : Lookup.getDefault().lookupAll(CreateFromTemplateHandler.class)) {
- FileObject current = entry.getFile();
- if (h.accept(current)) {
- if (params == null) {
- params = DataObject.CreateAction.findParameters(name);
- }
- FileObject fo = h.createFromTemplate(current, df.getPrimaryFile(), name,
- DataObject.CreateAction.enhanceParameters(params, name, current.getExt())
- );
- assert fo != null;
- continue NEXT_ENTRY;
- }
+ FileObject current = entry.getFile();
+ FileObject fo = FileBuilder.createFromTemplate(current, df.getPrimaryFile(), name, params, FileBuilder.Mode.FAIL);
+ if (fo == null) {
+ entry.createFromTemplate (df.getPrimaryFile (), name);
}
- entry.createFromTemplate (df.getPrimaryFile (), name);
}
try {
diff --git a/openide.loaders/test/unit/src/org/netbeans/modules/templates/Bug138973Test.java b/openide.loaders/test/unit/src/org/netbeans/modules/templates/Bug138973Test.java
deleted file mode 100644
--- a/openide.loaders/test/unit/src/org/netbeans/modules/templates/Bug138973Test.java
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2010 Oracle and/or its affiliates. All rights reserved.
- *
- * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
- * Other names may be trademarks of their respective owners.
- *
- * The contents of this file are subject to the terms of either the GNU
- * General Public License Version 2 only ("GPL") or the Common
- * Development and Distribution License("CDDL") (collectively, the
- * "License"). You may not use this file except in compliance with the
- * License. You can obtain a copy of the License at
- * http://www.netbeans.org/cddl-gplv2.html
- * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
- * specific language governing permissions and limitations under the
- * License. When distributing the software, include this License Header
- * Notice in each file and include the License file at
- * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the GPL Version 2 section of the License file that
- * accompanied this code. If applicable, add the following below the
- * License Header, with the fields enclosed by brackets [] replaced by
- * your own identifying information:
- * "Portions Copyrighted [year] [name of copyright owner]"
- *
- * If you wish your version of this file to be governed by only the CDDL
- * or only the GPL Version 2, indicate your decision by adding
- * "[Contributor] elects to include this software in this distribution
- * under the [CDDL or GPL Version 2] license." If you do not indicate a
- * single choice of license, a recipient has the option to distribute
- * your version of this file under either the CDDL, the GPL Version 2 or
- * to extend the choice of license to its licensees as provided above.
- * However, if you add GPL Version 2 code and therefore, elected the GPL
- * Version 2 license, then the option applies only if the new code is
- * made subject to such option by the copyright holder.
- *
- * Contributor(s):
- *
- * Portions Copyrighted 2008 Sun Microsystems, Inc.
- */
-
-package org.netbeans.modules.templates;
-
-import java.util.Enumeration;
-import org.openide.loaders.*;
-import java.io.BufferedReader;
-import java.io.BufferedWriter;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.io.Reader;
-import java.io.Writer;
-import java.nio.ByteBuffer;
-import java.nio.CharBuffer;
-import java.nio.charset.Charset;
-import java.nio.charset.CharsetDecoder;
-import java.nio.charset.CharsetEncoder;
-import java.nio.charset.CoderResult;
-import java.util.Map;
-import org.netbeans.api.queries.FileEncodingQuery;
-import org.netbeans.junit.MockServices;
-import org.netbeans.junit.NbTestCase;
-import org.netbeans.modules.openide.loaders.DataObjectEncodingQueryImplementation;
-import org.netbeans.spi.queries.FileEncodingQueryImplementation;
-import org.openide.filesystems.FileObject;
-import org.openide.filesystems.FileUtil;
-import org.openide.util.Enumerations;
-import org.openide.util.Lookup;
-import org.openide.util.lookup.Lookups;
-
-/**
- *
- * @author Marian Petras
- */
-public class Bug138973Test extends NbTestCase {
-
- private static final String TESTING_TEXT = "print('This is a testing text.')";
- private static final TestCharset TEST_CHARSET = new TestCharset();
- private static final String EXT = ".test";
- private static final String TEMPLATE_NAME = "Bug138973TestTemplate";
- private static final String TEMPLATE_NAME_EXT = TEMPLATE_NAME + EXT;
- private static final String TESTFILE_NAME = "testfile";
- private static final String TESTFILE_NAME_EXT = TESTFILE_NAME + EXT;
-
- public Bug138973Test(String n) {
- super(n);
- }
-
- public void testBug() throws Exception {
- MockServices.setServices(Pool.class, DataObjectEncodingQueryImplementation.class);
- FileUtil.setMIMEType("test", "text/test");
-
- FileUtil.createData(FileUtil.getConfigRoot(), "Editors/text/test/" + TestEncoding.class.getName().replace('.', '-') + ".instance");
-
- FileObject root = FileUtil.createMemoryFileSystem().getRoot();
- FileObject templatesFolder = root.createFolder("templates");
- assert templatesFolder != null;
- FileObject templateFile = FileUtil.createData(templatesFolder,
- TEMPLATE_NAME_EXT);
- templateFile.setAttribute ("template", Boolean.TRUE);
- templateFile.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js");
- byte[] templateBytes = TESTING_TEXT.getBytes("ISO-8859-1");
- InputStream source = new ByteArrayInputStream(templateBytes);
- OutputStream target = templateFile.getOutputStream();
- FileUtil.copy(source, target);
- target.close();
- source.close();
- assert templateFile.getSize() != 0L;
- templateFile.setAttribute("template", Boolean.TRUE);
-
- assertEquals("text/test", templateFile.getMIMEType());
-
- assertEquals("No Decoder yet", 0, TestCharset.newDecoder);
- DataObject templateDataObj = DataObject.find(templateFile);
- DataObject newDataObj= templateDataObj.createFromTemplate(
- DataFolder.findFolder(root),
- TESTFILE_NAME);
-
- assertTrue("Decoder created", TestCharset.newDecoder >= 1);
- }
-
- public static final class SimpleTemplateHandler extends CreateFromTemplateHandler {
- @Override
- protected boolean accept(FileObject orig) {
- return true;
- }
- @Override
- protected FileObject createFromTemplate(FileObject template,
- FileObject targetFolder,
- String name,
- Map parameters) throws IOException {
- String nameUniq = FileUtil.findFreeFileName(targetFolder, name, template.getExt());
- FileObject newFile = FileUtil.createData(targetFolder, nameUniq + '.' + template.getExt());
-
- Charset templateEnc = FileEncodingQuery.getEncoding(template);
- Charset newFileEnc = FileEncodingQuery.getEncoding(newFile);
-
- InputStream is = template.getInputStream();
- Reader reader = new BufferedReader(new InputStreamReader(is, templateEnc));
- OutputStream os = newFile.getOutputStream();
- Writer writer = new BufferedWriter(new OutputStreamWriter(os, newFileEnc));
- int cInt;
- while ((cInt = reader.read()) != -1) {
- writer.write(cInt);
- }
- writer.close();
- reader.close();
-
- return newFile;
- }
- }
-
- public static final class SimpleLoader extends MultiFileLoader {
- public SimpleLoader() {
- super(SimpleObject.class.getName());
- }
- protected String displayName() {
- return "SimpleLoader";
- }
- @Override
- protected FileObject findPrimaryFile(FileObject fo) {
- if (fo.getNameExt().equals(TEMPLATE_NAME_EXT)) {
- return fo;
- }
- if (fo.getNameExt().equals(TESTFILE_NAME_EXT)) {
- return fo;
- }
- return null;
- }
- @Override
- protected MultiDataObject createMultiObject(FileObject primaryFile)
- throws DataObjectExistsException,
- IOException {
- return new SimpleObject(this, primaryFile, isTestingFile(primaryFile));
- }
- @Override
- protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj,
- FileObject primaryFile) {
- return new FE(obj, primaryFile);
- }
- @Override
- protected MultiDataObject.Entry createSecondaryEntry(MultiDataObject obj,
- FileObject secondaryFile) {
- return new FE(obj, secondaryFile);
- }
- private static boolean isTestingFile(FileObject fileObj) {
- return fileObj.getNameExt().equals(TESTFILE_NAME_EXT);
- }
- }
-
- private static final class FE extends FileEntry {
- public FE(MultiDataObject mo, FileObject fo) {
- super(mo, fo);
- }
- @Override
- public FileObject createFromTemplate(FileObject f, String name) throws IOException {
- fail("FileEntry.createFromTemplate() should not be called");
- return null;
- }
- }
-
- public static final class SimpleObject extends MultiDataObject {
- private final Lookup lookup;
- public SimpleObject(SimpleLoader l,
- FileObject fo,
- boolean useSpecialEncoding)
- throws DataObjectExistsException {
- super(fo, l);
- lookup = useSpecialEncoding
- ? Lookups.fixed(this, new TestEncoding())
- : Lookups.singleton(this);
- }
- @Override
- public String getName() {
- return getPrimaryFile().getNameExt();
- }
- @Override
- public Lookup getLookup() {
- return lookup;
- }
- }
-
- public static final class TestEncoding extends FileEncodingQueryImplementation {
- @Override
- public Charset getEncoding(FileObject file) {
- return TEST_CHARSET;
- }
- }
-
- static final class TestCharset extends Charset {
- static int newDecoder;
- static int newEncoder;
-
- TestCharset() {
- super("test_charset", null);
- }
- @Override
- public boolean contains(Charset charset) {
- return true;
- }
- @Override
- public CharsetDecoder newDecoder() {
- newDecoder++;
- return Charset.forName("UTF-8").newDecoder();
- }
- @Override
- public CharsetEncoder newEncoder() {
- newEncoder++;
- return Charset.forName("UTF-8").newEncoder();
- }
- }
-
- public static final class Pool extends DataLoaderPool {
- @Override
- protected Enumeration extends DataLoader> loaders() {
- return Enumerations.singleton(SimpleLoader.getLoader(SimpleLoader.class));
- }
-
- }
-}
\ No newline at end of file
diff --git a/openide.loaders/test/unit/src/org/netbeans/modules/templates/IndentEngineIntTest.java b/openide.loaders/test/unit/src/org/netbeans/modules/templates/IndentEngineIntTest.java
deleted file mode 100644
--- a/openide.loaders/test/unit/src/org/netbeans/modules/templates/IndentEngineIntTest.java
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
- *
- * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
- * Other names may be trademarks of their respective owners.
- *
- * The contents of this file are subject to the terms of either the GNU
- * General Public License Version 2 only ("GPL") or the Common
- * Development and Distribution License("CDDL") (collectively, the
- * "License"). You may not use this file except in compliance with the
- * License. You can obtain a copy of the License at
- * http://www.netbeans.org/cddl-gplv2.html
- * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
- * specific language governing permissions and limitations under the
- * License. When distributing the software, include this License Header
- * Notice in each file and include the License file at
- * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the GPL Version 2 section of the License file that
- * accompanied this code. If applicable, add the following below the
- * License Header, with the fields enclosed by brackets [] replaced by
- * your own identifying information:
- * "Portions Copyrighted [year] [name of copyright owner]"
- *
- * Contributor(s):
- *
- * The Original Software is NetBeans. The Initial Developer of the Original
- * Software is Sun Microsystems, Inc.
- *
- * Portions Copyrighted 2007 Sun Microsystems, Inc.
- */
-
-package org.netbeans.modules.templates;
-
-import java.awt.Dialog;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.StringWriter;
-import java.io.Writer;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.Map;
-import javax.swing.text.Document;
-import org.netbeans.junit.MockServices;
-import org.netbeans.junit.NbTestCase;
-import org.openide.DialogDescriptor;
-import org.openide.DialogDisplayer;
-import org.openide.NotifyDescriptor;
-import org.openide.filesystems.FileObject;
-import org.openide.filesystems.FileUtil;
-import org.openide.loaders.DataFolder;
-import org.openide.loaders.DataLoader;
-import org.openide.loaders.DataLoaderPool;
-import org.openide.loaders.DataObject;
-import org.openide.loaders.DataObjectExistsException;
-import org.openide.loaders.FileEntry;
-import org.openide.loaders.MultiDataObject;
-import org.openide.loaders.MultiFileLoader;
-import org.openide.text.IndentEngine;
-import org.openide.util.Enumerations;
-
-/**
- *
- * @author Jaroslav Tulach
- */
-public class IndentEngineIntTest extends NbTestCase {
-
- public IndentEngineIntTest(String testName) {
- super(testName);
- }
-
- protected boolean runInEQ() {
- return true;
- }
-
-
- @SuppressWarnings("deprecation")
- protected void setUp() throws Exception {
- MockServices.setServices(DD.class, Pool.class, IEImpl.class);
- FileUtil.setMIMEType("txt", "text/jarda");
- }
-
- protected void tearDown() throws Exception {
- super.tearDown();
- }
-
- public void testCreateFromTemplateUsingFreemarker() throws Exception {
- FileObject root = FileUtil.createMemoryFileSystem().getRoot();
- FileObject fo = FileUtil.createData(root, "simpleObject.txt");
- OutputStream os = fo.getOutputStream();
- String txt = "print('
'); print(title); print('
');";
- os.write(txt.getBytes());
- os.close();
- fo.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "JavaScript");
-
-
- DataObject obj = DataObject.find(fo);
-
- DataFolder folder = DataFolder.findFolder(FileUtil.createFolder(root, "target"));
-
- Map parameters = Collections.singletonMap("title", "Nazdar");
- DataObject n = obj.createFromTemplate(folder, "complex", parameters);
-
- assertEquals("Created in right place", folder, n.getFolder());
- assertEquals("Created with right name", "complex.txt", n.getName());
-
- String exp = ">lmth/<>1h/1h<>lmth<";
- assertEquals(exp, stripNewLines(readFile(n.getPrimaryFile())));
-
- }
-
- static String stripNewLines(String str) {
- return str.replace("\n", "").replace("\r", "");
- }
-
- private static String readFile(FileObject fo) throws IOException {
- return fo.asText();
- }
-
- public static final class DD extends DialogDisplayer {
- public Object notify(NotifyDescriptor descriptor) {
- throw new UnsupportedOperationException("Not supported yet.");
- }
-
- public Dialog createDialog(final DialogDescriptor descriptor) {
- throw new UnsupportedOperationException("Not supported yet.");
- }
- }
-
- public static final class Pool extends DataLoaderPool {
- protected Enumeration loaders() {
- return Enumerations.singleton(SimpleLoader.getLoader(SimpleLoader.class));
- }
- }
-
- public static final class SimpleLoader extends MultiFileLoader {
- public SimpleLoader() {
- super(SimpleObject.class.getName());
- }
- protected String displayName() {
- return "SimpleLoader";
- }
- protected FileObject findPrimaryFile(FileObject fo) {
- if (fo.hasExt("prima")) {
- return fo;
- }
- return null;
- }
- protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException {
- return new SimpleObject(this, primaryFile);
- }
- protected MultiDataObject.Entry createPrimaryEntry(MultiDataObject obj, FileObject primaryFile) {
- return new FE(obj, primaryFile);
- }
- protected MultiDataObject.Entry createSecondaryEntry(MultiDataObject obj, FileObject secondaryFile) {
- return new FileEntry(obj, secondaryFile);
- }
- }
-
- private static final class FE extends FileEntry {
- public FE(MultiDataObject mo, FileObject fo) {
- super(mo, fo);
- }
-
- @Override
- public FileObject createFromTemplate(FileObject f, String name) throws IOException {
- fail("I do not want to be called");
- return null;
- }
-
-
-
- }
-
- public static final class SimpleObject extends MultiDataObject {
- public SimpleObject(SimpleLoader l, FileObject fo) throws DataObjectExistsException {
- super(fo, l);
- }
-
- public String getName() {
- return getPrimaryFile().getNameExt();
- }
- }
-
- public static final class IEImpl extends IndentEngine {
-
-
- public int indentLine(Document doc, int offset) {
- throw new UnsupportedOperationException("Not supported yet.");
- }
-
- public int indentNewLine(Document doc, int offset) {
- throw new UnsupportedOperationException("Not supported yet.");
- }
-
- @Override
- protected boolean acceptMimeType(String mime) {
- return "text/jarda".equals(mime); // NOI18N
- }
-
- public Writer createWriter(Document doc, int offset, final Writer writer) {
- class Rotate extends StringWriter {
- @Override
- public void close() throws IOException {
- super.close();
-
- String s = toString();
- StringBuilder sb = new StringBuilder(s.length());
- for (int i = s.length() - 1; i >= 0; i--) {
- sb.append(s.charAt(i));
- }
-
- writer.write(sb.toString());
- writer.close();
- }
- }
-
- assertNotNull("There is some document", doc);
- assertEquals("Its length is 0", 0, doc.getLength());
- assertEquals("Offset is 0", 0, offset);
-
- return new Rotate();
- }
-}
-}
diff --git a/openide.loaders/test/unit/src/org/netbeans/modules/templates/SCFTHandlerTest.java b/openide.loaders/test/unit/src/org/netbeans/modules/templates/SCFTHandlerTest.java
deleted file mode 100644
--- a/openide.loaders/test/unit/src/org/netbeans/modules/templates/SCFTHandlerTest.java
+++ /dev/null
@@ -1,507 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 1997-2010 Oracle and/or its affiliates. All rights reserved.
- *
- * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
- * Other names may be trademarks of their respective owners.
- *
- * The contents of this file are subject to the terms of either the GNU
- * General Public License Version 2 only ("GPL") or the Common
- * Development and Distribution License("CDDL") (collectively, the
- * "License"). You may not use this file except in compliance with the
- * License. You can obtain a copy of the License at
- * http://www.netbeans.org/cddl-gplv2.html
- * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
- * specific language governing permissions and limitations under the
- * License. When distributing the software, include this License Header
- * Notice in each file and include the License file at
- * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Oracle in the GPL Version 2 section of the License file that
- * accompanied this code. If applicable, add the following below the
- * License Header, with the fields enclosed by brackets [] replaced by
- * your own identifying information:
- * "Portions Copyrighted [year] [name of copyright owner]"
- *
- * Contributor(s):
- *
- * The Original Software is NetBeans. The Initial Developer of the Original
- * Software is Sun Microsystems, Inc.
- *
- * Portions Copyrighted 2007 Sun Microsystems, Inc.
- */
-
-package org.netbeans.modules.templates;
-
-import java.awt.Dialog;
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.OutputStream;
-import java.io.OutputStreamWriter;
-import java.nio.CharBuffer;
-import java.nio.charset.Charset;
-import java.util.Collections;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.Map;
-import java.util.logging.Level;
-import java.util.logging.Logger;
-import org.netbeans.junit.MockServices;
-import org.netbeans.junit.NbTestCase;
-import org.netbeans.spi.queries.FileEncodingQueryImplementation;
-import org.openide.DialogDescriptor;
-import org.openide.DialogDisplayer;
-import org.openide.NotifyDescriptor;
-import org.openide.filesystems.FileObject;
-import org.openide.filesystems.FileStateInvalidException;
-import org.openide.filesystems.FileSystem;
-import org.openide.filesystems.FileUtil;
-import org.openide.filesystems.LocalFileSystem;
-import org.openide.loaders.DataFolder;
-import org.openide.loaders.DataLoader;
-import org.openide.loaders.DataLoaderPool;
-import org.openide.loaders.DataObject;
-import org.openide.loaders.DataObjectExistsException;
-import org.openide.loaders.FileEntry;
-import org.openide.loaders.MultiDataObject;
-import org.openide.loaders.MultiFileLoader;
-import org.openide.util.Enumerations;
-
-/**
- *
- * @author Jaroslav Tulach
- */
-public class SCFTHandlerTest extends NbTestCase {
- static {
- // confuse the system a bit, if your system runs with UTF-8 default locale...
- //System.setProperty("file.encoding", "cp1252");
- }
-
- public SCFTHandlerTest(String testName) {
- super(testName);
- }
-
- @Override
- protected boolean runInEQ() {
- return true;
- }
-
- @Override
- protected Level logLevel() {
- return Level.FINE;
- }
-
- @Override
- protected void setUp() throws Exception {
- clearWorkDir();
- MockServices.setServices(DD.class, Pool.class, FEQI.class);
- }
-
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
- }
-
- public void testCreateFromTemplateUsingFreemarker() throws Exception {
- FileObject root = FileUtil.createMemoryFileSystem().getRoot();
- FileObject fo = FileUtil.createData(root, "simpleObject.txt");
- OutputStream os = fo.getOutputStream();
- String txt = "print('