All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.netbeans.api.templates.CreateFromTemplateHandler Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

package org.netbeans.api.templates;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.netbeans.api.annotations.common.NonNull;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;

/** This is an interface for smart templating that allows
 * any module to intercept calls to 
 * {@link FileBuilder#build()}
 * 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 FileBuilder#createFromTemplate(org.openide.filesystems.FileObject, org.openide.filesystems.FileObject, java.lang.String, java.util.Map, org.netbeans.api.templates.FileBuilder.Mode)} * is going to take place. * * @param desc describes the request that is about to be performed * @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; /** * Replaces ${param} tokens in a String. The parameter reference has syntax "${" paramName [":" defaultValue ] "}". * Parameters are replaced recursively. "${" can be escaped by \, so "\${" will not act as parameter reference start. * @param expression string template * @param parameters parameter values * @return evaluated string. */ static String mapParameters(String expression, Map parameters) { int start = 0; int pos = 0; StringBuilder sb = null; while ((pos = expression.indexOf("${", pos)) != -1) { // NOI18N if (pos > 0 && expression.charAt(pos - 1) == '\\') { // NOI18N pos += 2; continue; } int endPos = pos + 2; int state = 0; int nested = 0; A: while (endPos < expression.length()) { char c = expression.charAt(endPos); if (state == 1) { state = 0; endPos++; continue; } switch (c) { case '\\': // NOI18N state = 1; break; case '$': // NOI18N state = 2; break; case '{': // NOI18N if (state == 2) { state = 0; nested++; } break; case '}': // NOI18N if (state == 0) { if (nested-- == 0) { break A; } } break; } endPos++; } if (endPos >= expression.length()) { pos += 2; continue; } String token = expression.substring(pos + 2, endPos); String defValue = null; int colon = token.indexOf(':'); // NOI18N if (colon != -1) { defValue = token.substring(colon + 1); token = token.substring(0, colon); } Object v = parameters.get(token); if (v == null) { v = defValue; } if (v == null) { pos += 2; continue; } if (sb == null) { sb = new StringBuilder(); } sb.append(expression.substring(start, pos)).append(v.toString()); start = endPos + 1; pos = start; } if (sb == null) { return expression; } if (start < expression.length()) { sb.append(expression.substring(start)); } return mapParameters(sb.toString(), parameters); } private static final String PROP_TEMPLATE = "template"; // NOI18N /** * Prefix for template-controlling attributes. Such attributes will not be copied * during template instantiation. */ private static final String ATTR_TEMPLATE_PREFIX = "template."; /** * Copies template attributes over to the created file. Copies over from the source (template) to the target (usually * the produced file), except attributes that parametrize template creation. By default, attributes that are prefixed * with {@code "template."} are not copied. As the operation is not atomic, the method should be called in a * {@link org.openide.filesystems.FileSystem#runAtomicAction(org.openide.filesystems.FileSystem.AtomicAction)}. * The {@code "template"} attribute is never copied. * * @param h the Handler responsible for file creation, usually the calling handler. * @param from the original file * @param to the target file * @throws IOException if an I/O error occurs. */ public static void copyAttributesFromTemplate(CreateFromTemplateHandler h, FileObject from, FileObject to) throws IOException { // copy attributes; some attributes are filtered by FileSystems API already FileUtil.copyAttributes (from, to, (n, v) -> { if ("javax.script.ScriptEngine".equals(n) // NOI18N || n.startsWith(ATTR_TEMPLATE_PREFIX) || PROP_TEMPLATE.equals(n)) { return null; } else { return FileUtil.defaultAttributesTransformer().apply(n, v); } }); } /** * Copies the files or folders contained in the specified folder to the target. The original descriptor can be passed in, * since it has Lookup, parameters etc set up. They will be passed on to individual created files. The `contentsParent` may * be {@code null}, in which case the {@link CreateDescriptor#getTemplate()} folder will be used. * @param origDescriptor original descriptor to get parameters / lookup from * @param contentsParent template folder whose contents should be copied * @param target target folder * @return created files * @throws IOException * @since 1.23 */ protected static List defaultCopyContents(CreateDescriptor origDescriptor, FileObject contentsParent, FileObject target) throws IOException { if (contentsParent == null) { contentsParent = origDescriptor.getTemplate(); } if (contentsParent == null || !contentsParent.isFolder()) { throw new IllegalArgumentException("contentsParent is not a folder: " + contentsParent.getPath()); } List r = new ArrayList<>(); if (!origDescriptor.getParameters().containsKey("_noFolders")) { // NOI18N r.add(target); } for (FileObject child : origDescriptor.getTemplate().getChildren()) { Map parameters = new HashMap<>(origDescriptor.getParameters()); parameters.remove("name"); // NOI18N parameters.remove("nameAndExt"); // NOI18N // recursively instruct not to return folders unnecessarily parameters.put("_noFolders", Boolean.TRUE); // NOI18N FileBuilder b = new FileBuilder(child, target); b.defaultMode(FileBuilder.Mode.COPY) .useLookup(origDescriptor.getLookup()) .withParameters(parameters).createDescriptor(true); List files = b.build(); if (child.isFolder() || Boolean.TRUE.equals(child.getAttribute(FileBuilder.ATTR_TEMPLATE_OPEN_FILE))) { r.addAll(files); } } return r; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy