Added
Link Here
|
1 |
/* |
2 |
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. |
3 |
* |
4 |
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved. |
5 |
* |
6 |
* The contents of this file are subject to the terms of either the GNU |
7 |
* General Public License Version 2 only ("GPL") or the Common |
8 |
* Development and Distribution License("CDDL") (collectively, the |
9 |
* "License"). You may not use this file except in compliance with the |
10 |
* License. You can obtain a copy of the License at |
11 |
* http://www.netbeans.org/cddl-gplv2.html |
12 |
* or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the |
13 |
* specific language governing permissions and limitations under the |
14 |
* License. When distributing the software, include this License Header |
15 |
* Notice in each file and include the License file at |
16 |
* nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this |
17 |
* particular file as subject to the "Classpath" exception as provided |
18 |
* by Sun in the GPL Version 2 section of the License file that |
19 |
* accompanied this code. If applicable, add the following below the |
20 |
* License Header, with the fields enclosed by brackets [] replaced by |
21 |
* your own identifying information: |
22 |
* "Portions Copyrighted [year] [name of copyright owner]" |
23 |
* |
24 |
* Contributor(s): |
25 |
* |
26 |
* The Original Software is NetBeans. The Initial Developer of the Original |
27 |
* Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun |
28 |
* Microsystems, Inc. All Rights Reserved. |
29 |
* |
30 |
* If you wish your version of this file to be governed by only the CDDL |
31 |
* or only the GPL Version 2, indicate your decision by adding |
32 |
* "[Contributor] elects to include this software in this distribution |
33 |
* under the [CDDL or GPL Version 2] license." If you do not indicate a |
34 |
* single choice of license, a recipient has the option to distribute |
35 |
* your version of this file under either the CDDL, the GPL Version 2 or |
36 |
* to extend the choice of license to its licensees as provided above. |
37 |
* However, if you add GPL Version 2 code and therefore, elected the GPL |
38 |
* Version 2 license, then the option applies only if the new code is |
39 |
* made subject to such option by the copyright holder. |
40 |
*/ |
41 |
|
42 |
package org.netbeans.modules.settings.convertors; |
43 |
|
44 |
import java.util.Set; |
45 |
import javax.annotation.processing.Processor; |
46 |
import javax.annotation.processing.RoundEnvironment; |
47 |
import javax.annotation.processing.SupportedAnnotationTypes; |
48 |
import javax.annotation.processing.SupportedSourceVersion; |
49 |
import javax.lang.model.SourceVersion; |
50 |
import javax.lang.model.element.Element; |
51 |
import javax.lang.model.element.ExecutableElement; |
52 |
import javax.lang.model.element.Modifier; |
53 |
import javax.lang.model.element.TypeElement; |
54 |
import javax.lang.model.type.TypeKind; |
55 |
import javax.lang.model.type.TypeMirror; |
56 |
import javax.lang.model.util.ElementFilter; |
57 |
import org.netbeans.api.settings.ConvertAsProperties; |
58 |
import org.openide.filesystems.annotations.LayerBuilder.File; |
59 |
import org.openide.filesystems.annotations.LayerGeneratingProcessor; |
60 |
import org.openide.filesystems.annotations.LayerGenerationException; |
61 |
import org.openide.util.lookup.ServiceProvider; |
62 |
|
63 |
/** Processor to hide all the complexities of settings layer registration. |
64 |
* |
65 |
* @author Jaroslav Tulach <jtulach@netbeans.org> |
66 |
*/ |
67 |
@ServiceProvider(service=Processor.class) |
68 |
@SupportedSourceVersion(SourceVersion.RELEASE_6) |
69 |
@SupportedAnnotationTypes("org.netbeans.api.settings.ConvertAsProperties")//NOI18N |
70 |
public class ConvertorProcessor extends LayerGeneratingProcessor { |
71 |
|
72 |
|
73 |
@Override |
74 |
protected boolean handleProcess( |
75 |
Set<? extends TypeElement> annotations, |
76 |
RoundEnvironment env |
77 |
) throws LayerGenerationException { |
78 |
if (env.processingOver()) { |
79 |
return false; |
80 |
} |
81 |
|
82 |
for (Element e : env.getElementsAnnotatedWith(ConvertAsProperties.class)) { |
83 |
ConvertAsProperties reg = e.getAnnotation(ConvertAsProperties.class); |
84 |
|
85 |
String convElem = instantiableClassOrMethod(e); |
86 |
final String dtd = reg.dtd(); |
87 |
|
88 |
String dtdCode = convertPublicId(dtd); |
89 |
|
90 |
/* |
91 |
<folder name="xml"> |
92 |
<folder name="entities"> |
93 |
<folder name="NetBeans_org_netbeans_modules_settings_xtest"> |
94 |
<file name="DTD_XML_FooSetting_1_0" url="nbres:/org/netbeans/modules/settings/resources/properties-1_0.dtd"> |
95 |
<attr name="hint.originalPublicID" stringvalue="-//NetBeans org.netbeans.modules.settings.xtest//DTD XML FooSetting 1.0//EN"/> |
96 |
*/ |
97 |
layer(e).file("xml/entities" + dtdCode). |
98 |
url("nbres:/org/netbeans/modules/settings/resources/properties-1_0.dtd"). |
99 |
stringvalue("hint.originalPublicID", dtd).write(); |
100 |
/* |
101 |
<folder name="memory"> |
102 |
<folder name="org"> |
103 |
<folder name="netbeans"> |
104 |
<folder name="modules"> |
105 |
<folder name="settings"> |
106 |
<folder name="convertors"> |
107 |
<file name="FooSetting"> |
108 |
<attr name="settings.providerPath" |
109 |
stringvalue="xml/lookups/NetBeans_org_netbeans_modules_settings_xtest/DTD_XML_FooSetting_1_0.instance"/> |
110 |
*/ |
111 |
layer(e).file("xml/memory/" + convElem.replace('.', '/')). |
112 |
stringvalue("settings.providerPath", "xml/lookups/" + dtdCode + ".instance"). |
113 |
write(); |
114 |
|
115 |
/* |
116 |
<folder name="lookups"> |
117 |
<folder name="NetBeans_org_netbeans_modules_settings_xtest"> |
118 |
<file name="DTD_XML_FooSetting_1_0.instance"> |
119 |
<attr name="instanceCreate" methodvalue="org.netbeans.api.settings.Factory.create"/> |
120 |
<attr name="settings.convertor" methodvalue="org.netbeans.api.settings.Factory.properties"/> |
121 |
<attr name="settings.instanceClass" stringvalue="org.netbeans.modules.settings.convertors.FooSetting"/> |
122 |
<attr name="settings.instanceOf" stringvalue="org.netbeans.modules.settings.convertors.FooSetting"/> |
123 |
</file> |
124 |
</folder> |
125 |
*/ |
126 |
File f = layer(e).file("xml/lookups" + dtdCode + ".instance"). |
127 |
methodvalue("instanceCreate", "org.netbeans.api.settings.Factory", "create"). |
128 |
methodvalue("settings.convertor", "org.netbeans.api.settings.Factory", "properties"). |
129 |
stringvalue("settings.instanceClass", convElem). |
130 |
stringvalue("settings.instanceOf", convElem). |
131 |
boolvalue("xmlproperties.preventStoring", !reg.autostore()); |
132 |
commaSeparated(f, reg.ignoreChanges()).write(); |
133 |
} |
134 |
return false; |
135 |
} |
136 |
|
137 |
/** Copied from FileEntityResolver from o.n.core module. |
138 |
*/ |
139 |
@SuppressWarnings("fallthrough") |
140 |
private static String convertPublicId (String publicID) { |
141 |
char[] arr = publicID.toCharArray (); |
142 |
|
143 |
|
144 |
int numberofslashes = 0; |
145 |
int state = 0; |
146 |
int write = 0; |
147 |
OUT: for (int i = 0; i < arr.length; i++) { |
148 |
char ch = arr[i]; |
149 |
|
150 |
switch (state) { |
151 |
case 0: |
152 |
// initial state |
153 |
if (ch == '+' || ch == '-' || ch == 'I' || ch == 'S' || ch == 'O') { |
154 |
// do not write that char |
155 |
continue; |
156 |
} |
157 |
// switch to regular state |
158 |
state = 1; |
159 |
// fallthru |
160 |
case 1: |
161 |
// regular state expecting any character |
162 |
if (ch == '/') { |
163 |
state = 2; |
164 |
if (++numberofslashes == 3) { |
165 |
// last part of the ID, exit |
166 |
break OUT; |
167 |
} |
168 |
arr[write++] = '/'; |
169 |
continue; |
170 |
} |
171 |
break; |
172 |
case 2: |
173 |
// previous character was / |
174 |
if (ch == '/') { |
175 |
// ignore second / and write nothing |
176 |
continue; |
177 |
} |
178 |
state = 1; |
179 |
break; |
180 |
} |
181 |
|
182 |
// write the char into the array |
183 |
if (ch >= 'A' && ch <= 'Z' || ch >= 'a' && ch <= 'z' || ch >= '0' && ch <= '9') { |
184 |
arr[write++] = ch; |
185 |
} else { |
186 |
arr[write++] = '_'; |
187 |
} |
188 |
} |
189 |
|
190 |
return new String (arr, 0, write); |
191 |
} |
192 |
|
193 |
private static File commaSeparated(File f, String[] arr) { |
194 |
if (arr.length == 0) { |
195 |
return f; |
196 |
} |
197 |
|
198 |
StringBuilder sb = new StringBuilder(); |
199 |
String sep = ""; |
200 |
for (String s : arr) { |
201 |
sb.append(sep); |
202 |
sb.append(s); |
203 |
sep = ","; |
204 |
} |
205 |
return f.stringvalue("xmlproperties.ignoreChanges", sb.toString()); |
206 |
} |
207 |
|
208 |
private String instantiableClassOrMethod(Element e) throws IllegalArgumentException, LayerGenerationException { |
209 |
switch (e.getKind()) { |
210 |
case CLASS: { |
211 |
String clazz = processingEnv.getElementUtils().getBinaryName((TypeElement) e).toString(); |
212 |
if (e.getModifiers().contains(Modifier.ABSTRACT)) { |
213 |
throw new LayerGenerationException(clazz + " must not be abstract", e); |
214 |
} |
215 |
{ |
216 |
boolean hasDefaultCtor = false; |
217 |
for (ExecutableElement constructor : ElementFilter.constructorsIn(e.getEnclosedElements())) { |
218 |
if (constructor.getParameters().isEmpty()) { |
219 |
hasDefaultCtor = true; |
220 |
break; |
221 |
} |
222 |
} |
223 |
if (!hasDefaultCtor) { |
224 |
throw new LayerGenerationException(clazz + " must have a no-argument constructor", e); |
225 |
} |
226 |
} |
227 |
TypeMirror propType; |
228 |
propType = processingEnv.getElementUtils().getTypeElement("java.util.Properties").asType(); |
229 |
{ |
230 |
boolean hasRead = false; |
231 |
boolean hasWrite = false; |
232 |
for (ExecutableElement m : ElementFilter.methodsIn(e.getEnclosedElements())) { |
233 |
if ( |
234 |
m.getParameters().size() == 1 && |
235 |
m.getSimpleName().contentEquals("readProperties") && |
236 |
m.getParameters().get(0).asType().equals(propType) |
237 |
) { |
238 |
hasRead = true; |
239 |
} |
240 |
if ( |
241 |
m.getParameters().size() == 1 && |
242 |
m.getSimpleName().contentEquals("writeProperties") && |
243 |
m.getParameters().get(0).asType().equals(propType) && |
244 |
m.getReturnType().getKind() == TypeKind.VOID |
245 |
) { |
246 |
hasWrite = true; |
247 |
} |
248 |
} |
249 |
if (!hasRead) { |
250 |
throw new LayerGenerationException(clazz + " must have proper readProperties method", e); |
251 |
} |
252 |
if (!hasWrite) { |
253 |
throw new LayerGenerationException(clazz + " must have proper writeProperties method", e); |
254 |
} |
255 |
} |
256 |
return clazz; |
257 |
} |
258 |
default: |
259 |
throw new IllegalArgumentException("Annotated element is not loadable as an instance: " + e); |
260 |
} |
261 |
} |
262 |
} |