diff --git a/api.templates/arch.xml b/api.templates/arch.xml new file mode 100644 --- /dev/null +++ b/api.templates/arch.xml @@ -0,0 +1,446 @@ + + +]> + + + + &api-questions; + + +

+ 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. + +

+
+ +

+ No. +

+
+ +

+ Yes. +

+
+ +

+ None. +

+
+ +

+ None. +

+
+ +

+ None. +

+
+ +

+ Yes, looks up CreateFromTemplateAttributes + and CreateFromTemplateHandler. +

+
+ +

+ 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: + *

+ * + * @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): + *

content="resources/empty.php"
+ *

For a form template: + *

content={"Login.java.template", "Login.form.template"}
+ */ + 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 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 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(title); 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 exp = "

Nazdar

"; + assertEquals(exp, readFile(n.getPrimaryFile())); + + } + + public void testCreateWithNameAndExt() throws Exception { + FileObject root = FileUtil.createMemoryFileSystem().getRoot(); + FileObject fo = FileUtil.createData(root, "simpleObject.txt"); + OutputStream os = fo.getOutputStream(); + String txt = "print('

'); print(nameAndExt); 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.emptyMap(); + 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 = "

complex.txt

"; + assertEquals(exp, readFile(n.getPrimaryFile())); + + } + + public void testCreateWithNameAndExtForForm() throws Exception { + LocalFileSystem lfs = new LocalFileSystem(); + lfs.setRootDirectory(getWorkDir()); + FileObject root = lfs.getRoot(); + FileObject fo = FileUtil.createData(root, "j.java"); + OutputStream os = fo.getOutputStream(); + String txt = "print('

'); print(nameAndExt); print('

')"; + os.write(txt.getBytes()); + os.close(); + fo.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js"); + + FileObject fo2 = FileUtil.createData(root, "j.form"); + OutputStream os2 = fo2.getOutputStream(); + String txt2 = "print('

'); print(nameAndExt); print('

')"; + os2.write(txt2.getBytes()); + os2.close(); + fo2.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js"); + + DataObject obj = DataObject.find(fo); + assertEquals("Both files", 2, obj.files().size()); + + DataFolder folder = DataFolder.findFolder(FileUtil.createFolder(root, "target")); + + Map parameters = Collections.emptyMap(); + DataObject n = obj.createFromTemplate(folder, "complex", parameters); + + assertEquals("Two files", 2, n.files().size()); + + + FileObject newForm = FileUtil.findBrother(n.getPrimaryFile(), "form"); + + assertEquals("Primary file is java", "java", n.getPrimaryFile().getExt()); + + assertNotNull("Form copied", newForm); + DataObject frm = DataObject.find(newForm); + assertSame("Form belongs to java", n, frm); + + assertEquals("Created in right place", folder, n.getFolder()); + assertEquals("Created with right name", "complex", n.getName()); + + String exp = "

complex.java

"; + assertEquals("Primary file" + n.getPrimaryFile(), exp, readFile(n.getPrimaryFile())); + + String exp2 = "

complex.form

"; + assertEquals(exp2, readFile(newForm)); + } + + public void testBasePropertiesAlwaysPresent() throws Exception { + FileObject root = FileUtil.createMemoryFileSystem().getRoot(); + FileObject fo = FileUtil.createData(root, "simpleObject.txt"); + OutputStream os = fo.getOutputStream(); + String txt = "print('

'); print(name); print('

');" + + "print('

'); print(date); print('

');" + + "print('

'); print(time); print('

');" + + "print('

'); print(user); print('

');" + + "print('

'); print(dateTime.getTime()); 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): - *

content="resources/empty.php"
- *

For a form template: - *

content={"Login.java.template", "Login.form.template"}
- */ - 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 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 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('

'); print(title); 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 exp = "

Nazdar

"; - assertEquals(exp, readFile(n.getPrimaryFile())); - - } - - public void testCreateWithNameAndExt() throws Exception { - FileObject root = FileUtil.createMemoryFileSystem().getRoot(); - FileObject fo = FileUtil.createData(root, "simpleObject.txt"); - OutputStream os = fo.getOutputStream(); - String txt = "print('

'); print(nameAndExt); 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.emptyMap(); - 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 = "

complex.txt

"; - assertEquals(exp, readFile(n.getPrimaryFile())); - - } - - public void testCreateWithNameAndExtForForm() throws Exception { - LocalFileSystem lfs = new LocalFileSystem(); - lfs.setRootDirectory(getWorkDir()); - FileObject root = lfs.getRoot(); - FileObject fo = FileUtil.createData(root, "j.java"); - OutputStream os = fo.getOutputStream(); - String txt = "print('

'); print(nameAndExt); print('

')"; - os.write(txt.getBytes()); - os.close(); - fo.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js"); - - FileObject fo2 = FileUtil.createData(root, "j.form"); - OutputStream os2 = fo2.getOutputStream(); - String txt2 = "print('

'); print(nameAndExt); print('

')"; - os2.write(txt2.getBytes()); - os2.close(); - fo2.setAttribute(ScriptingCreateFromTemplateHandler.SCRIPT_ENGINE_ATTR, "js"); - - DataObject obj = DataObject.find(fo); - assertEquals("Both files", 2, obj.files().size()); - - DataFolder folder = DataFolder.findFolder(FileUtil.createFolder(root, "target")); - - Map parameters = Collections.emptyMap(); - DataObject n = obj.createFromTemplate(folder, "complex", parameters); - - assertEquals("Two files", 2, n.files().size()); - - - FileObject newForm = FileUtil.findBrother(n.getPrimaryFile(), "form"); - - assertEquals("Primary file is java", "java", n.getPrimaryFile().getExt()); - - assertNotNull("Form copied", newForm); - DataObject frm = DataObject.find(newForm); - assertSame("Form belongs to java", n, frm); - - assertEquals("Created in right place", folder, n.getFolder()); - assertEquals("Created with right name", "complex", n.getName()); - - String exp = "

complex.java

"; - assertEquals("Primary file" + n.getPrimaryFile(), exp, readFile(n.getPrimaryFile())); - - String exp2 = "

complex.form

"; - assertEquals(exp2, readFile(newForm)); - } - - public void testBasePropertiesAlwaysPresent() throws Exception { - FileObject root = FileUtil.createMemoryFileSystem().getRoot(); - FileObject fo = FileUtil.createData(root, "simpleObject.txt"); - OutputStream os = fo.getOutputStream(); - String txt = "print('

'); print(name); print('

');" + - "print('

'); print(date); print('

');" + - "print('

'); print(time); print('

');" + - "print('

'); print(user); print('

');" + - "print('

'); print(dateTime.getTime()); 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/openide.loaders/test/unit/src/org/netbeans/modules/templates/ScriptingCreateFromTemplateTest.java b/openide.loaders/test/unit/src/org/netbeans/modules/templates/ScriptingCreateFromTemplateTest.java deleted file mode 100644 --- a/openide.loaders/test/unit/src/org/netbeans/modules/templates/ScriptingCreateFromTemplateTest.java +++ /dev/null @@ -1,235 +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.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/openide.loaders/test/unit/src/org/netbeans/modules/templates/utf8.xml b/openide.loaders/test/unit/src/org/netbeans/modules/templates/utf8.xml deleted file mode 100644 --- a/openide.loaders/test/unit/src/org/netbeans/modules/templates/utf8.xml +++ /dev/null @@ -1,4 +0,0 @@ -println(''); -println(''); -println(' Žluťoučký kůň skákal přes čtvero mezí.'); -println(''); diff --git a/openide.loaders/test/unit/src/org/openide/loaders/CreateFromTemplateHandlerTest.java b/openide.loaders/test/unit/src/org/openide/loaders/CreateFromTemplateHandlerTest.java --- a/openide.loaders/test/unit/src/org/openide/loaders/CreateFromTemplateHandlerTest.java +++ b/openide.loaders/test/unit/src/org/openide/loaders/CreateFromTemplateHandlerTest.java @@ -205,12 +205,12 @@ public static String name; public static Map parameters; - protected boolean accept(FileObject fo) { + public boolean accept(FileObject fo) { acceptObject.add(fo); return true; } - protected FileObject createFromTemplate( + public FileObject createFromTemplate( FileObject orig, FileObject f, String n, Map p ) throws IOException {