001: /*
002: * Spoon - http://spoon.gforge.inria.fr/
003: * Copyright (C) 2006 INRIA Futurs <renaud.pawlak@inria.fr>
004: *
005: * This software is governed by the CeCILL-C License under French law and
006: * abiding by the rules of distribution of free software. You can use, modify
007: * and/or redistribute the software under the terms of the CeCILL-C license as
008: * circulated by CEA, CNRS and INRIA at http://www.cecill.info.
009: *
010: * This program is distributed in the hope that it will be useful, but WITHOUT
011: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
012: * FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details.
013: *
014: * The fact that you are presently reading this means that you have had
015: * knowledge of the CeCILL-C license and that you accept its terms.
016: */
017:
018: package spoon.processing;
019:
020: import java.io.FileNotFoundException;
021: import java.io.IOException;
022: import java.lang.reflect.Field;
023: import java.lang.reflect.Method;
024: import java.util.HashSet;
025: import java.util.Set;
026:
027: import spoon.reflect.Factory;
028: import spoon.reflect.declaration.CtClass;
029: import spoon.reflect.declaration.CtElement;
030: import spoon.support.util.RtHelper;
031:
032: /**
033: * This class defines an abstract processor to be subclassed by the user for
034: * defining new processors.
035: */
036: public abstract class AbstractProcessor<E extends CtElement> implements
037: Processor<E> {
038:
039: Factory factory;
040:
041: Set<Class<? extends CtElement>> processedElementTypes = new HashSet<Class<? extends CtElement>>();
042:
043: /**
044: * Empty constructor only for all processors (invoked by Spoon).
045: */
046: @SuppressWarnings("unchecked")
047: public AbstractProcessor() {
048: super ();
049: for (Method m : getClass().getMethods()) {
050: if (m.getName().equals("process")
051: && (m.getParameterTypes().length == 1)) {
052: Class c = m.getParameterTypes()[0];
053: if (CtElement.class != c) {
054: addProcessedElementType(c);
055: }
056: }
057: }
058: if (processedElementTypes.isEmpty()) {
059: addProcessedElementType(CtElement.class);
060: }
061: }
062:
063: /**
064: * Adds a processed element type. This method is typically invoked in
065: * subclasses' constructors.
066: */
067: protected void addProcessedElementType(
068: Class<? extends CtElement> elementType) {
069: processedElementTypes.add(elementType);
070: }
071:
072: /**
073: * Clears the processed element types.
074: */
075: protected void clearProcessedElementType() {
076: processedElementTypes.clear();
077: }
078:
079: public Environment getEnvironment() {
080: return getFactory().getEnvironment();
081: }
082:
083: public Factory getFactory() {
084: return this .factory;
085: }
086:
087: public Set<Class<? extends CtElement>> getProcessedElementTypes() {
088: return processedElementTypes;
089: }
090:
091: /**
092: * Helper method to load the properties of the given processor (uses
093: * {@link Environment#getProcessorProperties(String)}).
094: */
095: public static ProcessorProperties loadProperties(Processor<?> p) {
096: ProcessorProperties props = null;
097: try {
098: props = p.getFactory().getEnvironment()
099: .getProcessorProperties(p.getClass().getName());
100: } catch (FileNotFoundException e) {
101: p.getFactory().getEnvironment().debugMessage(
102: "property file not found for processor '"
103: + p.getClass().getName() + "'");
104: } catch (IOException e) {
105: p.getFactory().getEnvironment().report(
106: p,
107: Severity.ERROR,
108: "wrong properties file format for processor '"
109: + p.getClass().getName() + "'");
110: e.printStackTrace();
111: } catch (Exception e) {
112: p.getFactory().getEnvironment().report(
113: p,
114: Severity.ERROR,
115: "unable to get properties for processor '"
116: + p.getClass().getName() + "': "
117: + e.getMessage());
118: e.printStackTrace();
119: }
120: return props;
121: }
122:
123: public TraversalStrategy getTraversalStrategy() {
124: return TraversalStrategy.PRE_ORDER;
125: }
126:
127: public void init() {
128: // loadProperties();
129: }
130:
131: public final void initProperties(ProcessorProperties properties) {
132: initProperties(this , properties);
133: }
134:
135: public boolean isToBeProcessed(E candidate) {
136: if (candidate instanceof CtClass) {
137: if (factory.Template().getAll().containsKey(
138: ((CtClass<?>) candidate).getQualifiedName())) {
139: return false;
140: }
141: }
142: return true;
143: }
144:
145: /**
146: * Helper method to initialize the properties of a given processor.
147: */
148: public static void initProperties(Processor<?> p,
149: ProcessorProperties properties) {
150: if (properties != null) {
151: for (Field f : RtHelper.getAllFields(p.getClass())) {
152: if (f.isAnnotationPresent(Property.class)) {
153: Object obj = properties.get(f.getType(), f
154: .getName());
155: if (obj != null) {
156: f.setAccessible(true);
157: try {
158: f.set(p, obj);
159: } catch (Exception e) {
160: e.printStackTrace();
161: }
162: } else {
163: p.getFactory().getEnvironment().report(
164: p,
165: Severity.WARNING,
166: "No value found for property '"
167: + f.getName()
168: + "' in processor "
169: + p.getClass().getName());
170: }
171: }
172: }
173: }
174: }
175:
176: /**
177: * The manual meta-model processing cannot be overriden (use
178: * {@link AbstractManualProcessor}) to do so.
179: */
180: public final void process() {
181: }
182:
183: public void processingDone() {
184: // do nothing by default
185: }
186:
187: /**
188: * Removes a processed element type.
189: */
190: protected void removeProcessedElementType(
191: Class<? extends CtElement> elementType) {
192: processedElementTypes.remove(elementType);
193: }
194:
195: public void setFactory(Factory factory) {
196: this.factory = factory;
197: }
198:
199: }
|