blob: d3c230fe895277dac2d74cb1f3886e1345d791b3 [file] [log] [blame]
/*
* Copyright 2000-2013 JetBrains s.r.o.
*
* Licensed 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 com.intellij.ide.fileTemplates.impl;
import com.intellij.ide.fileTemplates.FileTemplateManager;
import com.intellij.ide.plugins.IdeaPluginDescriptorImpl;
import com.intellij.ide.plugins.PluginManagerCore;
import com.intellij.ide.plugins.cl.PluginClassLoader;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.extensions.PluginDescriptor;
import com.intellij.openapi.fileTypes.ex.FileTypeManagerEx;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.util.lang.UrlClassLoader;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.text.MessageFormat;
import java.util.*;
/**
* Serves as a container for all existing template manager types and loads corresponding templates upon creation (at construction time).
*
* @author Rustam Vishnyakov
*/
public class FileTemplatesLoader {
private static final Logger LOG = Logger.getInstance("#" + FileTemplatesLoader.class.getName());
private static final String TEMPLATES_DIR = "fileTemplates";
private static final String DEFAULT_TEMPLATES_ROOT = TEMPLATES_DIR;
public static final String DESCRIPTION_FILE_EXTENSION = "html";
private static final String DESCRIPTION_EXTENSION_SUFFIX = "." + DESCRIPTION_FILE_EXTENSION;
//static final String DESCRIPTION_FILE_NAME = "default." + DESCRIPTION_FILE_EXTENSION;
private final FTManager myDefaultTemplatesManager;
private final FTManager myInternalTemplatesManager;
private final FTManager myPatternsManager;
private final FTManager myCodeTemplatesManager;
private final FTManager myJ2eeTemplatesManager;
private final Map<String, FTManager> myDirToManagerMap = new HashMap<String, FTManager>();
private final FTManager[] myAllManagers;
private static final String INTERNAL_DIR = "internal";
private static final String INCLUDES_DIR = "includes";
private static final String CODETEMPLATES_DIR = "code";
private static final String J2EE_TEMPLATES_DIR = "j2ee";
private static final String ROOT_DIR = ".";
private final FileTypeManagerEx myTypeManager;
private URL myDefaultTemplateDescription;
private URL myDefaultIncludeDescription;
public FileTemplatesLoader(@NotNull FileTypeManagerEx typeManager) {
myTypeManager = typeManager;
myDefaultTemplatesManager = new FTManager(FileTemplateManager.DEFAULT_TEMPLATES_CATEGORY, ROOT_DIR);
myInternalTemplatesManager = new FTManager(FileTemplateManager.INTERNAL_TEMPLATES_CATEGORY, INTERNAL_DIR, true);
myPatternsManager = new FTManager(FileTemplateManager.INCLUDES_TEMPLATES_CATEGORY, INCLUDES_DIR);
myCodeTemplatesManager = new FTManager(FileTemplateManager.CODE_TEMPLATES_CATEGORY, CODETEMPLATES_DIR);
myJ2eeTemplatesManager = new FTManager(FileTemplateManager.J2EE_TEMPLATES_CATEGORY, J2EE_TEMPLATES_DIR);
myAllManagers = new FTManager[]{
myDefaultTemplatesManager,
myInternalTemplatesManager,
myPatternsManager,
myCodeTemplatesManager,
myJ2eeTemplatesManager};
myDirToManagerMap.put("", myDefaultTemplatesManager);
myDirToManagerMap.put(INTERNAL_DIR + "/", myInternalTemplatesManager);
myDirToManagerMap.put(INCLUDES_DIR + "/", myPatternsManager);
myDirToManagerMap.put(CODETEMPLATES_DIR + "/", myCodeTemplatesManager);
myDirToManagerMap.put(J2EE_TEMPLATES_DIR + "/", myJ2eeTemplatesManager);
loadDefaultTemplates();
for (FTManager child : myAllManagers) {
loadCustomizedContent(child);
}
}
@NotNull
public FTManager[] getAllManagers() {
return myAllManagers;
}
@NotNull
public FTManager getDefaultTemplatesManager() {
return myDefaultTemplatesManager;
}
@NotNull
public FTManager getInternalTemplatesManager() {
return myInternalTemplatesManager;
}
public FTManager getPatternsManager() {
return myPatternsManager;
}
public FTManager getCodeTemplatesManager() {
return myCodeTemplatesManager;
}
public FTManager getJ2eeTemplatesManager() {
return myJ2eeTemplatesManager;
}
public URL getDefaultTemplateDescription() {
return myDefaultTemplateDescription;
}
public URL getDefaultIncludeDescription() {
return myDefaultIncludeDescription;
}
private void loadDefaultTemplates() {
final Set<URL> processedUrls = new HashSet<URL>();
for (PluginDescriptor plugin : PluginManagerCore.getPlugins()) {
if (plugin instanceof IdeaPluginDescriptorImpl && ((IdeaPluginDescriptorImpl)plugin).isEnabled()) {
final ClassLoader loader = plugin.getPluginClassLoader();
if (loader instanceof PluginClassLoader && ((PluginClassLoader)loader).getUrls().isEmpty()) {
continue; // development mode, when IDEA_CORE's loader contains all the classpath
}
try {
final Enumeration<URL> systemResources = loader.getResources(DEFAULT_TEMPLATES_ROOT);
if (systemResources != null && systemResources.hasMoreElements()) {
while (systemResources.hasMoreElements()) {
final URL url = systemResources.nextElement();
if (processedUrls.contains(url)) {
continue;
}
processedUrls.add(url);
loadDefaultsFromRoot(url);
}
}
}
catch (IOException e) {
LOG.error(e);
}
}
}
}
private void loadDefaultsFromRoot(final URL root) throws IOException {
final List<String> children = UrlUtil.getChildrenRelativePaths(root);
if (children.isEmpty()) {
return;
}
final Set<String> descriptionPaths = new HashSet<String>();
for (String path : children) {
if (path.equals("default.html")) {
myDefaultTemplateDescription = UrlClassLoader.internProtocol(new URL(root.toExternalForm() + "/" + path));
}
else if (path.equals("includes/default.html")) {
myDefaultIncludeDescription = UrlClassLoader.internProtocol(new URL(root.toExternalForm() + "/" + path));
}
else if (path.endsWith(DESCRIPTION_EXTENSION_SUFFIX)) {
descriptionPaths.add(path);
}
}
for (final String path : children) {
for (Map.Entry<String, FTManager> entry : myDirToManagerMap.entrySet()) {
final String prefix = entry.getKey();
if (matchesPrefix(path, prefix)) {
if (path.endsWith(FTManager.TEMPLATE_EXTENSION_SUFFIX)) {
final String filename = path.substring(prefix.length(), path.length() - FTManager.TEMPLATE_EXTENSION_SUFFIX.length());
final String extension = myTypeManager.getExtension(filename);
final String templateName = filename.substring(0, filename.length() - extension.length() - 1);
final URL templateUrl = UrlClassLoader.internProtocol(new URL(root.toExternalForm() + "/" + path));
final String descriptionPath = getDescriptionPath(prefix, templateName, extension, descriptionPaths);
final URL descriptionUrl = descriptionPath != null ? UrlClassLoader.internProtocol(new URL(root.toExternalForm() + "/" + descriptionPath)) : null;
entry.getValue().addDefaultTemplate(new DefaultTemplate(templateName, extension, templateUrl, descriptionUrl));
}
break; // FTManagers loop
}
}
}
}
void loadCustomizedContent(FTManager manager) {
final File configRoot = manager.getConfigRoot(false);
final File[] configFiles = configRoot.listFiles();
if (configFiles == null) {
return;
}
final List<File> templateWithDefaultExtension = new ArrayList<File>();
final Set<String> processedNames = new HashSet<String>();
for (File file : configFiles) {
if (file.isDirectory() || myTypeManager.isFileIgnored(file.getName()) || file.isHidden()) {
continue;
}
final String name = file.getName();
if (name.endsWith(FTManager.TEMPLATE_EXTENSION_SUFFIX)) {
templateWithDefaultExtension.add(file);
}
else {
processedNames.add(name);
addTemplateFromFile(manager, name, file);
}
}
for (File file : templateWithDefaultExtension) {
String name = file.getName();
// cut default template extension
name = name.substring(0, name.length() - FTManager.TEMPLATE_EXTENSION_SUFFIX.length());
if (!processedNames.contains(name)) {
addTemplateFromFile(manager, name, file);
}
FileUtil.delete(file);
}
}
private static void addTemplateFromFile(FTManager manager, String fileName, File file) {
Pair<String,String> nameExt = FTManager.decodeFileName(fileName);
final String extension = nameExt.second;
final String templateQName = nameExt.first;
if (templateQName.length() == 0) {
return;
}
try {
final String text = FileUtil.loadFile(file, FTManager.CONTENT_ENCODING);
manager.addTemplate(templateQName, extension).setText(text);
}
catch (IOException e) {
LOG.error(e);
}
}
private static boolean matchesPrefix(String path, String prefix) {
if (prefix.length() == 0) {
return !path.contains("/");
}
return FileUtil.startsWith(path, prefix) && !path.substring(prefix.length()).contains("/");
}
//Example: templateName="NewClass" templateExtension="java"
@Nullable
private static String getDescriptionPath(String pathPrefix, String templateName, String templateExtension, Set<String> descriptionPaths) {
final Locale locale = Locale.getDefault();
String descName = MessageFormat
.format("{0}.{1}_{2}_{3}" + DESCRIPTION_EXTENSION_SUFFIX, templateName, templateExtension,
locale.getLanguage(), locale.getCountry());
String descPath = pathPrefix.length() > 0 ? pathPrefix + descName : descName;
if (descriptionPaths.contains(descPath)) {
return descPath;
}
descName = MessageFormat.format("{0}.{1}_{2}" + DESCRIPTION_EXTENSION_SUFFIX, templateName, templateExtension, locale.getLanguage());
descPath = pathPrefix.length() > 0 ? pathPrefix + descName : descName;
if (descriptionPaths.contains(descPath)) {
return descPath;
}
descName = templateName + "." + templateExtension + DESCRIPTION_EXTENSION_SUFFIX;
descPath = pathPrefix.length() > 0 ? pathPrefix + descName : descName;
if (descriptionPaths.contains(descPath)) {
return descPath;
}
return null;
}
}