001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: * $Header:$
018: */
019: package org.apache.beehive.netui.compiler;
020:
021: import org.apache.beehive.netui.compiler.typesystem.declaration.AnnotationInstance;
022: import org.apache.beehive.netui.compiler.typesystem.declaration.AnnotationTypeElementDeclaration;
023: import org.apache.beehive.netui.compiler.typesystem.declaration.AnnotationValue;
024: import org.apache.beehive.netui.compiler.typesystem.declaration.Declaration;
025: import org.apache.beehive.netui.compiler.typesystem.declaration.MemberDeclaration;
026: import org.apache.beehive.netui.compiler.typesystem.env.CoreAnnotationProcessorEnv;
027:
028: import java.util.HashMap;
029: import java.util.HashSet;
030: import java.util.Iterator;
031: import java.util.List;
032: import java.util.Map;
033: import java.util.Set;
034:
035: /**
036: * Our base class for customizable annotation tag grammars. It has stock behavior for basic
037: * things like making sure required attributes exist, and provides plugin points for more
038: * complex checks.
039: */
040: public abstract class AnnotationGrammar implements JpfLanguageConstants {
041: /**
042: * If this tag requires a particular runtime version...
043: */
044: private String _requiredRuntimeVersion = null;
045: private RuntimeVersionChecker _runtimeVersionChecker;
046: private CoreAnnotationProcessorEnv _env;
047: private Diagnostics _diagnostics;
048: private Map _memberGrammars = new HashMap();
049: private Map _memberArrayGrammars = new HashMap();
050: private Map _memberTypes = new HashMap();
051:
052: /**
053: * @param requiredRuntimeVersion causes an error to be produced if the version in the manifest of beehive-netui-pageflow.jar
054: * is not high enough.
055: */
056: protected AnnotationGrammar(CoreAnnotationProcessorEnv env,
057: Diagnostics diags, String requiredRuntimeVersion,
058: RuntimeVersionChecker runtimeVersionChecker) {
059: _env = env;
060: _diagnostics = diags;
061: _runtimeVersionChecker = runtimeVersionChecker;
062: _requiredRuntimeVersion = requiredRuntimeVersion;
063: }
064:
065: public final CoreAnnotationProcessorEnv getEnv() {
066: return _env;
067: }
068:
069: public Diagnostics getDiagnostics() {
070: return _diagnostics;
071: }
072:
073: public final Object check(AnnotationInstance annotation,
074: AnnotationInstance[] parentAnnotations,
075: MemberDeclaration classMember)
076: throws FatalCompileTimeException {
077: return check(annotation, parentAnnotations, classMember, -1);
078: }
079:
080: public final Object check(AnnotationInstance annotation,
081: AnnotationInstance[] parentAnnotations,
082: MemberDeclaration classMember, int annotationArrayIndex)
083: throws FatalCompileTimeException {
084: if (!beginCheck(annotation, parentAnnotations, classMember))
085: return null;
086:
087: Map valuesPresent = annotation.getElementValues();
088: HashSet wasPresent = new HashSet();
089: HashMap checkResults = new HashMap();
090:
091: if (parentAnnotations == null)
092: parentAnnotations = new AnnotationInstance[0];
093: int oldLen = parentAnnotations.length;
094: AnnotationInstance[] parentsIncludingMe = new AnnotationInstance[oldLen + 1];
095: System.arraycopy(parentAnnotations, 0, parentsIncludingMe, 0,
096: oldLen);
097: parentsIncludingMe[oldLen] = annotation;
098:
099: for (Iterator ii = valuesPresent.entrySet().iterator(); ii
100: .hasNext();) {
101: Map.Entry i = (Map.Entry) ii.next();
102: AnnotationTypeElementDeclaration decl = (AnnotationTypeElementDeclaration) i
103: .getKey();
104: AnnotationValue value = (AnnotationValue) i.getValue();
105: String memberName = decl.getSimpleName();
106:
107: wasPresent.add(memberName);
108: onCheckMember(decl, value, annotation, parentAnnotations,
109: classMember);
110: Object grammarOrType = null;
111:
112: if ((grammarOrType = _memberGrammars.get(memberName)) != null) {
113: AnnotationGrammar childGrammar = (AnnotationGrammar) grammarOrType;
114:
115: if (childGrammar != null) // it will be non-null unless there are other, more basic, errors
116: {
117: Object result = childGrammar.check(
118: (AnnotationInstance) value.getValue(),
119: parentsIncludingMe, classMember);
120:
121: if (result != null) {
122: checkResults.put(memberName, result);
123: }
124: }
125: } else if ((grammarOrType = _memberArrayGrammars
126: .get(memberName)) != null) {
127: AnnotationGrammar arrayGrammar = (AnnotationGrammar) grammarOrType;
128:
129: if (arrayGrammar != null) {
130: List annotations = CompilerUtils
131: .getAnnotationArray(value);
132:
133: for (int j = 0; j < annotations.size(); ++j) {
134: Object annotationInstance = annotations.get(j);
135: // The user may have included something other than an annotation in the array. The compiler
136: // will print an error; this is to prevent a ClassCastException here.
137: if (annotationInstance instanceof AnnotationInstance) {
138: AnnotationInstance ann = (AnnotationInstance) annotationInstance;
139: arrayGrammar.check(ann, parentsIncludingMe,
140: classMember, j);
141: }
142: }
143: }
144: } else {
145: AnnotationMemberType memberType = (AnnotationMemberType) _memberTypes
146: .get(memberName);
147:
148: if (memberType != null) // it will be non-null unless there are other, more basic, errors
149: {
150: Object result = memberType.check(decl, value,
151: parentsIncludingMe, classMember,
152: annotationArrayIndex);
153: if (result != null)
154: checkResults.put(memberName, result);
155: }
156: }
157: }
158:
159: return endCheck(annotation, parentAnnotations, classMember,
160: wasPresent, checkResults);
161: }
162:
163: public final boolean beginCheck(AnnotationInstance annotation,
164: AnnotationInstance[] parentAnnotations,
165: MemberDeclaration classMember)
166: throws FatalCompileTimeException {
167: //
168: // First check to see if there's a required runtime version.
169: //
170: if (!_runtimeVersionChecker.checkRuntimeVersion(
171: _requiredRuntimeVersion, annotation, _diagnostics,
172: "error.required-runtime-version-annotation",
173: new Object[] { PAGEFLOW_RUNTIME_JAR })) {
174: return false;
175: }
176:
177: return onBeginCheck(annotation, parentAnnotations, classMember); // for derived classes
178: }
179:
180: protected void addError(Declaration element, String key) {
181: getDiagnostics().addError(element, key, null);
182: }
183:
184: protected void addError(Declaration element, String key,
185: Object[] args) {
186: getDiagnostics().addErrorArrayArgs(element, key, args);
187: }
188:
189: protected void addError(Declaration element, String key, Object arg) {
190: getDiagnostics().addError(element, key, arg);
191: }
192:
193: protected void addError(Declaration element, String key,
194: Object arg1, Object arg2) {
195: getDiagnostics().addError(element, key, arg1, arg2);
196: }
197:
198: protected void addError(Declaration element, String key,
199: Object arg1, Object arg2, Object arg3) {
200: getDiagnostics().addError(element, key, arg1, arg2, arg3);
201: }
202:
203: protected void addError(AnnotationValue element, String key) {
204: getDiagnostics().addError(element, key, null);
205: }
206:
207: protected void addError(AnnotationValue element, String key,
208: Object[] args) {
209: getDiagnostics().addErrorArrayArgs(element, key, args);
210: }
211:
212: protected void addError(AnnotationValue element, String key,
213: Object arg1) {
214: getDiagnostics().addError(element, key, arg1);
215: }
216:
217: protected void addError(AnnotationValue element, String key,
218: Object arg1, Object arg2) {
219: getDiagnostics().addError(element, key, arg1, arg2);
220: }
221:
222: protected void addError(AnnotationValue element, String key,
223: Object arg1, Object arg2, Object arg3) {
224: getDiagnostics().addError(element, key, arg1, arg2, arg3);
225: }
226:
227: protected void addError(AnnotationInstance element, String key) {
228: getDiagnostics().addError(element, key, null);
229: }
230:
231: protected void addError(AnnotationInstance element, String key,
232: Object[] args) {
233: getDiagnostics().addErrorArrayArgs(element, key, args);
234: }
235:
236: protected void addError(AnnotationInstance element, String key,
237: Object arg1) {
238: getDiagnostics().addError(element, key, arg1);
239: }
240:
241: protected void addError(AnnotationInstance element, String key,
242: Object arg1, Object arg2) {
243: getDiagnostics().addError(element, key, arg1, arg2);
244: }
245:
246: protected void addError(AnnotationInstance element, String key,
247: Object arg1, Object arg2, Object arg3) {
248: getDiagnostics().addError(element, key, arg1, arg2, arg3);
249: }
250:
251: protected void addWarning(Declaration element, String key) {
252: getDiagnostics().addWarning(element, key, null);
253: }
254:
255: protected void addWarning(Declaration element, String key,
256: Object[] args) {
257: getDiagnostics().addWarningArrayArgs(element, key, args);
258: }
259:
260: protected void addWarning(Declaration element, String key,
261: Object arg) {
262: getDiagnostics().addWarning(element, key, arg);
263: }
264:
265: protected void addWarning(Declaration element, String key,
266: Object arg1, Object arg2) {
267: getDiagnostics().addWarning(element, key, arg1, arg2);
268: }
269:
270: protected void addWarning(Declaration element, String key,
271: Object arg1, Object arg2, Object arg3) {
272: getDiagnostics().addWarning(element, key, arg1, arg2, arg3);
273: }
274:
275: protected void addWarning(AnnotationValue element, String key) {
276: getDiagnostics().addWarning(element, key, null);
277: }
278:
279: protected void addWarning(AnnotationValue element, String key,
280: Object[] args) {
281: getDiagnostics().addWarningArrayArgs(element, key, args);
282: }
283:
284: protected void addWarning(AnnotationValue element, String key,
285: Object arg1) {
286: getDiagnostics().addWarning(element, key, arg1);
287: }
288:
289: protected void addWarning(AnnotationValue element, String key,
290: Object arg1, Object arg2) {
291: getDiagnostics().addWarning(element, key, arg1, arg2);
292: }
293:
294: protected void addWarning(AnnotationValue element, String key,
295: Object arg1, Object arg2, Object arg3) {
296: getDiagnostics().addWarning(element, key, arg1, arg2, arg3);
297: }
298:
299: protected void addWarning(AnnotationInstance element, String key) {
300: getDiagnostics().addWarning(element, key, null);
301: }
302:
303: protected void addWarning(AnnotationInstance element, String key,
304: Object[] args) {
305: getDiagnostics().addWarningArrayArgs(element, key, args);
306: }
307:
308: protected void addWarning(AnnotationInstance element, String key,
309: Object arg1) {
310: getDiagnostics().addWarning(element, key, arg1);
311: }
312:
313: protected void addWarning(AnnotationInstance element, String key,
314: Object arg1, Object arg2) {
315: getDiagnostics().addWarning(element, key, arg1, arg2);
316: }
317:
318: protected void addWarning(AnnotationInstance element, String key,
319: Object arg1, Object arg2, Object arg3) {
320: getDiagnostics().addWarning(element, key, arg1, arg2, arg3);
321: }
322:
323: /**
324: * @return a result (any Object) that will be passed back to the parent checker. May be null</code>.
325: */
326: public final Object endCheck(AnnotationInstance annotation,
327: AnnotationInstance[] parentAnnotations,
328: MemberDeclaration classMember, Set wasPresent,
329: Map checkResults) {
330: //
331: // Check mutually-exclusive attributes and child annotations.
332: //
333: String[][] mutuallyExclusiveAttrs = getMutuallyExclusiveAttrs();
334: for (int i = 0; mutuallyExclusiveAttrs != null
335: && i < mutuallyExclusiveAttrs.length; ++i) {
336: String alreadyFound = null;
337:
338: for (int j = 0; j < mutuallyExclusiveAttrs[i].length; ++j) {
339: String this Attr = mutuallyExclusiveAttrs[i][j];
340:
341: if (wasPresent.contains(this Attr)) {
342: if (alreadyFound == null) {
343: alreadyFound = this Attr;
344: } else {
345: String errorKey = "error.atmost-one-may-exist-"
346: + mutuallyExclusiveAttrs[i].length;
347: getDiagnostics().addErrorArrayArgs(annotation,
348: errorKey, mutuallyExclusiveAttrs[i]);
349: }
350: }
351: }
352: }
353:
354: //
355: // Check required attributes and child annotations.
356: //
357: String[][] requiredAttrs = getRequiredAttrs();
358: for (int i = 0; requiredAttrs != null
359: && i < requiredAttrs.length; ++i) {
360: boolean foundOne = false;
361:
362: for (int j = 0; j < requiredAttrs[i].length; ++j) {
363: String this Attr = requiredAttrs[i][j];
364:
365: if (wasPresent.contains(this Attr)) {
366: foundOne = true;
367: break;
368: }
369: }
370:
371: if (!foundOne) {
372: String errorKey = "error.atleast-one-must-exist-"
373: + requiredAttrs[i].length;
374: getDiagnostics().addErrorArrayArgs(annotation,
375: errorKey, requiredAttrs[i]);
376: }
377: }
378:
379: //
380: // Check inter-dependencies for attributes and child annotations.
381: //
382: String[][] attrDependencies = getAttrDependencies();
383: for (int i = 0; attrDependencies != null
384: && i < attrDependencies.length; ++i) {
385: String this Attr = attrDependencies[i][0];
386:
387: if (wasPresent.contains(this Attr)) {
388: boolean foundOne = false;
389:
390: for (int j = 1; j < attrDependencies[i].length; ++j) {
391: if (wasPresent.contains(attrDependencies[i][j])) {
392: foundOne = true;
393: break;
394: }
395: }
396:
397: if (!foundOne) {
398: String key = "error.attr-dependency-not-found-"
399: + (attrDependencies[i].length - 1);
400: getDiagnostics().addErrorArrayArgs(annotation, key,
401: attrDependencies[i]);
402: }
403: }
404: }
405:
406: return onEndCheck(annotation, parentAnnotations, classMember,
407: checkResults); // for derived classes
408: }
409:
410: protected boolean onBeginCheck(AnnotationInstance annotation,
411: AnnotationInstance[] parentAnnotations,
412: MemberDeclaration classMember)
413: throws FatalCompileTimeException {
414: return true;
415: }
416:
417: /**
418: * @param checkResults map of member-name (String) -> result-from-checking (Object)
419: * @return a result (any Object) that will be passed back to the parent checker. May be null</code>.
420: */
421: protected Object onEndCheck(AnnotationInstance annotation,
422: AnnotationInstance[] parentAnnotations,
423: MemberDeclaration classMember, Map checkResults) {
424: return null;
425: }
426:
427: protected void onCheckMember(
428: AnnotationTypeElementDeclaration memberDecl,
429: AnnotationValue member, AnnotationInstance annotation,
430: AnnotationInstance[] parentAnnotations,
431: MemberDeclaration classMember) {
432: }
433:
434: /**
435: * Each entry in this array (a String[]) lists mutually exclusive attributes.
436: */
437: public String[][] getMutuallyExclusiveAttrs() {
438: return null;
439: }
440:
441: /**
442: * Each entry in this array (a String[]) lists attributes of which one must exist in this tag.
443: */
444: public String[][] getRequiredAttrs() {
445: return null;
446: }
447:
448: /**
449: * Each entry in this array (a String[]) is an array whose first element is an attribute that
450: * requires at least one of the subsequent elements to exist as an attribute.
451: */
452: public String[][] getAttrDependencies() {
453: return null;
454: }
455:
456: protected void addMemberGrammar(String memberName,
457: AnnotationGrammar grammar) {
458: _memberGrammars.put(memberName, grammar);
459: }
460:
461: protected void addMemberArrayGrammar(String memberName,
462: AnnotationGrammar grammar) {
463: _memberArrayGrammars.put(memberName, grammar);
464: }
465:
466: protected void addMemberType(String memberName,
467: AnnotationMemberType type) {
468: _memberTypes.put(memberName, type);
469: }
470:
471: public String getRequiredRuntimeVersion() {
472: return _requiredRuntimeVersion;
473: }
474:
475: public RuntimeVersionChecker getRuntimeVersionChecker() {
476: return _runtimeVersionChecker;
477: }
478: }
|