Cleanup: NotNull/Nullable
[idea/community.git] / java / java-impl / src / com / intellij / psi / util / CreateClassUtil.java
1 /*
2  * Copyright 2000-2014 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.psi.util;
17
18 import com.intellij.ide.fileTemplates.FileTemplate;
19 import com.intellij.ide.fileTemplates.FileTemplateManager;
20 import com.intellij.ide.fileTemplates.JavaCreateFromTemplateHandler;
21 import com.intellij.ide.util.PackageUtil;
22 import com.intellij.openapi.application.ApplicationManager;
23 import com.intellij.openapi.diagnostic.Logger;
24 import com.intellij.openapi.fileTypes.StdFileTypes;
25 import com.intellij.openapi.module.Module;
26 import com.intellij.openapi.project.Project;
27 import com.intellij.openapi.util.text.StringUtil;
28 import com.intellij.psi.*;
29 import com.intellij.psi.codeStyle.JavaCodeStyleManager;
30 import com.intellij.util.IncorrectOperationException;
31 import com.intellij.util.text.StringTokenizer;
32 import org.jetbrains.annotations.NonNls;
33 import org.jetbrains.annotations.NotNull;
34 import org.jetbrains.annotations.Nullable;
35
36 import java.io.IOException;
37 import java.util.Map;
38 import java.util.Properties;
39
40 /**
41  * author: lesya
42  */
43 public class CreateClassUtil {
44   private static final Logger LOG = Logger.getInstance("#com.intellij.j2ee.CreateClassUtil");
45
46   @NonNls public static final String DEFAULT_CLASS_TEMPLATE = "#DEFAULT_CLASS_TEMPLATE";
47   @NonNls private static final String DO_NOT_CREATE_CLASS_TEMPLATE = "#DO_NOT_CREATE_CLASS_TEMPLATE";
48   @NonNls private static final String CLASS_NAME_PROPERTY = "Class_Name";
49   @NonNls private static final String INTERFACE_NAME_PROPERTY = "Interface_Name";
50
51   private CreateClassUtil() {}
52
53   @Nullable
54   private static PsiClass createClassFromTemplate(@NotNull final Properties attributes, @Nullable final String templateName,
55                                                   @NotNull final PsiDirectory directoryRoot,
56                                                   @NotNull final String className) throws IncorrectOperationException {
57     if (templateName == null) return null;
58     if (templateName.equals(DO_NOT_CREATE_CLASS_TEMPLATE)) return null;
59
60     final Project project = directoryRoot.getProject();
61     try {
62       final PsiDirectory directory = createParentDirectories(directoryRoot, className);
63       final PsiFile psiFile = directory.findFile(className + "." + StdFileTypes.JAVA.getDefaultExtension());
64       if (psiFile != null) {
65         psiFile.delete();
66       }
67
68       final String rawClassName = extractClassName(className);
69       final PsiFile existing = directory.findFile(rawClassName + ".java");
70       if (existing instanceof PsiJavaFile) {
71         final PsiClass[] classes = ((PsiJavaFile)existing).getClasses();
72         if (classes.length > 0) {
73           return classes[0];
74         }
75         return null;
76       }
77
78       final PsiClass aClass;
79       if (templateName.equals(DEFAULT_CLASS_TEMPLATE)) {
80         aClass = JavaDirectoryService.getInstance().createClass(directory, rawClassName);
81       }
82       else {
83         final FileTemplateManager fileTemplateManager = FileTemplateManager.getInstance(project);
84         FileTemplate fileTemplate = fileTemplateManager.getJ2eeTemplate(templateName);
85         LOG.assertTrue(fileTemplate != null, templateName + " not found");
86         final String text = fileTemplate.getText(attributes);
87         aClass = JavaCreateFromTemplateHandler.createClassOrInterface(project, directory, text, true, fileTemplate.getExtension());
88       }
89       return (PsiClass)JavaCodeStyleManager.getInstance(project).shortenClassReferences(aClass);
90     }
91     catch (IOException e) {
92       throw new IncorrectOperationException(e);
93     }
94   }
95
96   @NotNull
97   private static PsiDirectory createParentDirectories(@NotNull PsiDirectory directoryRoot, @NotNull String className) throws IncorrectOperationException {
98     final PsiPackage currentPackage = JavaDirectoryService.getInstance().getPackage(directoryRoot);
99     final String packagePrefix = currentPackage == null? null : currentPackage.getQualifiedName() + ".";
100     final String packageName = extractPackage(packagePrefix != null && className.startsWith(packagePrefix)?
101                                               className.substring(packagePrefix.length()) : className);
102     final StringTokenizer tokenizer = new StringTokenizer(packageName, ".");
103     while (tokenizer.hasMoreTokens()) {
104       String packagePart = tokenizer.nextToken();
105       PsiDirectory subdirectory = directoryRoot.findSubdirectory(packagePart);
106       if (subdirectory == null) {
107         directoryRoot.checkCreateSubdirectory(packagePart);
108         subdirectory = directoryRoot.createSubdirectory(packagePart);
109       }
110       directoryRoot = subdirectory;
111     }
112     return directoryRoot;
113   }
114
115   public static String extractClassName(String fqName) {
116     return StringUtil.getShortName(fqName);
117   }
118
119   public static String extractPackage(String fqName) {
120     int i = fqName.lastIndexOf('.');
121     return i == -1 ? "" : fqName.substring(0, i);
122   }
123
124   public static String makeFQName(String aPackage, String className) {
125     String fq = aPackage;
126     if (!"".equals(aPackage)) {
127       fq += ".";
128     }
129     fq += className;
130     return fq;
131   }
132
133   @Nullable
134   public static PsiClass createClassNamed(String newClassName, String templateName, @NotNull PsiDirectory directory) throws IncorrectOperationException {
135     return createClassNamed(newClassName, FileTemplateManager.getInstance(directory.getProject()).getDefaultProperties(), templateName, directory);
136   }
137
138   @Nullable
139   public static PsiClass createClassNamed(String newClassName, Map classProperties, String templateName, @NotNull PsiDirectory directory)
140     throws IncorrectOperationException {
141     Properties defaultProperties = FileTemplateManager.getInstance(directory.getProject()).getDefaultProperties();
142     Properties properties = new Properties(defaultProperties);
143     properties.putAll(classProperties);
144
145     return createClassNamed(newClassName, properties, templateName, directory);
146   }
147
148   @Nullable
149   private static PsiClass createClassNamed(@Nullable String newClassName,
150                                            @NotNull Properties properties,
151                                            String templateName,
152                                            @NotNull PsiDirectory directory) throws IncorrectOperationException {
153     if (newClassName == null) {
154       return null;
155     }
156     final String className = extractClassName(newClassName);
157     properties.setProperty(CLASS_NAME_PROPERTY, className);
158     properties.setProperty(INTERFACE_NAME_PROPERTY, className);
159
160     return createClassFromTemplate(properties, templateName, directory, newClassName);
161   }
162
163   @Nullable
164   public static PsiClass createClassFromCustomTemplate(@Nullable PsiDirectory classDirectory, 
165                                                        @Nullable final Module module,
166                                                        final String className,
167                                                        final String templateName) {
168     if (classDirectory == null && module != null) {
169       try {
170         classDirectory = PackageUtil.findOrCreateDirectoryForPackage(module, "", null, false);
171       }
172       catch (IncorrectOperationException e) {
173         return null;
174       }
175     }
176     if (classDirectory == null) {
177       return null;
178     }
179     try {
180       final Properties properties = ApplicationManager.getApplication().isUnitTestMode() ?
181                                     new Properties() :
182                                     FileTemplateManager.getInstance(classDirectory.getProject()).getDefaultProperties();
183       return createClassNamed(className, new Properties(properties), templateName, classDirectory);
184     }
185     catch (IncorrectOperationException e) {
186       LOG.error(e);
187       return null;
188     }
189   }
190 }