001: /*******************************************************************************
002: * Copyright (c) 2005, 2007 BEA Systems, Inc.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * wharley@bea.com - initial API and implementation
010: *******************************************************************************/package org.eclipse.jdt.apt.core.internal.util;
011:
012: import java.io.File;
013: import java.util.Collections;
014: import java.util.LinkedHashMap;
015: import java.util.Map;
016:
017: import org.eclipse.core.runtime.CoreException;
018: import org.eclipse.core.runtime.IPath;
019: import org.eclipse.core.runtime.Status;
020: import org.eclipse.jdt.apt.core.internal.AptPlugin;
021: import org.eclipse.jdt.apt.core.internal.FactoryPluginManager;
022: import org.eclipse.jdt.apt.core.util.IFactoryPath;
023:
024: /**
025: * Provides access to the annotation processor factory path for a Java project.
026: * This class should not be instantiated or subclassed.
027: *
028: * The factory path is an ordered Map<FactoryContainer, FactoryPath.Attributes>.
029: * Containers are things like jar files or plugins, that contain one or more
030: * annotation processor factories. In the context of a particular project,
031: * processors are given precedence according to the order of their container on
032: * the factory path; and they are executed according to the container's attributes
033: * on the factory path.
034: */
035: public class FactoryPath implements IFactoryPath {
036:
037: /**
038: * Attributes of entries on the factory path. These belong here,
039: * rather than on FactoryContainer itself, because the same container
040: * might have different attributes in different projects - e.g., it
041: * might be enabled in one project and disabled in another.
042: */
043: public static class Attributes {
044: /** Should this container's processors be executed? */
045: private boolean _enabled;
046: /** Should this container's processors execute in Sun apt compatibility mode? (Slow and limiting!) */
047: private boolean _runInBatchMode;
048:
049: // CONSTRUCTORS
050: public Attributes(boolean enabled, boolean runInBatchMode) {
051: _enabled = enabled;
052: _runInBatchMode = runInBatchMode;
053: }
054:
055: public Attributes(Attributes attr) {
056: _enabled = attr._enabled;
057: _runInBatchMode = attr._runInBatchMode;
058: }
059:
060: // SUPPORT
061: public boolean equals(Object o) {
062: if (o == null || !(o instanceof Attributes))
063: return false;
064: Attributes oA = (Attributes) o;
065: return (_enabled == oA._enabled)
066: && (_runInBatchMode == oA._runInBatchMode);
067: }
068:
069: public int hashCode() {
070: return (_enabled ? 1 : 0) + (_runInBatchMode ? 2 : 0);
071: }
072:
073: // GETTERS
074: public boolean isEnabled() {
075: return _enabled;
076: }
077:
078: public boolean runInBatchMode() {
079: return _runInBatchMode;
080: }
081:
082: // SETTERS
083: public void setEnabled(boolean enabled) {
084: _enabled = enabled;
085: }
086:
087: public void setRunInBatchMode(boolean runInBatchMode) {
088: _runInBatchMode = runInBatchMode;
089: }
090: }
091:
092: /**
093: * The factory path.
094: */
095: private final Map<FactoryContainer, Attributes> _path = Collections
096: .synchronizedMap(new LinkedHashMap<FactoryContainer, Attributes>());
097:
098: /* (non-Javadoc)
099: * @see org.eclipse.jdt.apt.core.util.IFactoryPath#addExternalJar(java.io.File)
100: */
101: public void addExternalJar(File jar) {
102: FactoryContainer fc = FactoryPathUtil
103: .newExtJarFactoryContainer(jar);
104: Attributes a = new Attributes(true, false);
105: internalAdd(fc, a);
106: }
107:
108: /* (non-Javadoc)
109: * @see org.eclipse.jdt.apt.core.util.IFactoryPath#removeExternalJar(java.io.File)
110: */
111: public void removeExternalJar(File jar) {
112: FactoryContainer fc = FactoryPathUtil
113: .newExtJarFactoryContainer(jar);
114: _path.remove(fc);
115: }
116:
117: /* (non-Javadoc)
118: * @see org.eclipse.jdt.apt.core.util.IFactoryPath#addVarJar(org.eclipse.core.runtime.IPath)
119: */
120: public void addVarJar(IPath jarPath) {
121: FactoryContainer fc = FactoryPathUtil
122: .newVarJarFactoryContainer(jarPath);
123: Attributes a = new Attributes(true, false);
124: internalAdd(fc, a);
125: }
126:
127: /* (non-Javadoc)
128: * @see org.eclipse.jdt.apt.core.util.IFactoryPath#removeVarJar(org.eclipse.core.runtime.IPath)
129: */
130: public void removeVarJar(IPath jarPath) {
131: FactoryContainer fc = FactoryPathUtil
132: .newVarJarFactoryContainer(jarPath);
133: _path.remove(fc);
134: }
135:
136: /* (non-Javadoc)
137: * @see org.eclipse.jdt.apt.core.util.IFactoryPath#addWkspJar(org.eclipse.core.runtime.IPath)
138: */
139: public void addWkspJar(IPath jarPath) {
140: FactoryContainer fc = FactoryPathUtil
141: .newWkspJarFactoryContainer(jarPath);
142: Attributes a = new Attributes(true, false);
143: internalAdd(fc, a);
144: }
145:
146: /* (non-Javadoc)
147: * @see org.eclipse.jdt.apt.core.util.IFactoryPath#removeWkspJar(org.eclipse.core.runtime.IPath)
148: */
149: public void removeWkspJar(IPath jarPath) {
150: FactoryContainer fc = FactoryPathUtil
151: .newWkspJarFactoryContainer(jarPath);
152: _path.remove(fc);
153: }
154:
155: /* (non-Javadoc)
156: * @see org.eclipse.jdt.apt.core.util.IFactoryPath#enablePlugin(java.lang.String)
157: */
158: public void enablePlugin(String pluginId) throws CoreException {
159: FactoryContainer fc = FactoryPluginManager
160: .getPluginFactoryContainer(pluginId);
161: Attributes a = _path.get(fc);
162: if (a == null) {
163: Status status = AptPlugin
164: .createWarningStatus(
165: new IllegalArgumentException(),
166: "Specified plugin was not found, so it could not be added to the annotation processor factory path: " + pluginId); //$NON-NLS-1$
167: throw new CoreException(status);
168: }
169: a.setEnabled(true);
170: internalAdd(fc, a);
171: }
172:
173: /* (non-Javadoc)
174: * @see org.eclipse.jdt.apt.core.util.IFactoryPath#disablePlugin(java.lang.String)
175: */
176: public void disablePlugin(String pluginId) {
177: FactoryContainer fc = FactoryPluginManager
178: .getPluginFactoryContainer(pluginId);
179: Attributes a = _path.get(fc);
180: if (a != null) {
181: a.setEnabled(false);
182: }
183: }
184:
185: /**
186: * Add a single factory container to the head of the FactoryPath,
187: * and save the new path to the appropriate settings file.
188: * If the container specified is already in the project's list in
189: * some other FactoryPathEntry, the existing entry will be removed
190: * before the new one is added.
191: * @param fc must not be null.
192: */
193: public void addEntryToHead(FactoryContainer fc, boolean enabled,
194: boolean runInBatchMode) {
195: Attributes a = new Attributes(enabled, runInBatchMode);
196: internalAdd(fc, a);
197: }
198:
199: /**
200: * Set the factory path based on the contents of an ordered map.
201: * @param map should be an ordered map, such as LinkedHashMap; should contain no
202: * nulls; and should contain no duplicate FactoryContainers.
203: */
204: public void setContainers(Map<FactoryContainer, Attributes> map) {
205: synchronized (_path) {
206: _path.clear();
207: _path.putAll(map);
208: }
209: }
210:
211: /**
212: * Add a factory container, and attributes, to the head of the list.
213: * If it already existed in the list, remove the old instance before
214: * adding the new one.
215: * <p>
216: * @param fc must not be null
217: * @param a must not be null
218: */
219: private void internalAdd(FactoryContainer fc, Attributes a) {
220: synchronized (_path) {
221: _path.remove(fc);
222: // LinkedHashMap doesn't have any way to add to the head,
223: // so we're forced to do two copies. Make the new map
224: // large enough that we don't have to rehash midway through the putAll().
225: Map<FactoryContainer, Attributes> newPath = new LinkedHashMap<FactoryContainer, Attributes>(
226: 1 + 4 * (_path.size() + 1) / 3);
227: newPath.put(fc, a);
228: newPath.putAll(_path);
229: _path.clear();
230: _path.putAll(newPath);
231: }
232: }
233:
234: public Map<FactoryContainer, Attributes> getEnabledContainers() {
235: Map<FactoryContainer, Attributes> map = new LinkedHashMap<FactoryContainer, Attributes>();
236: synchronized (_path) {
237: for (Map.Entry<FactoryContainer, Attributes> entry : _path
238: .entrySet()) {
239: Attributes attr = entry.getValue();
240: if (attr.isEnabled()) {
241: Attributes attrClone = new Attributes(attr);
242: map.put(entry.getKey(), attrClone);
243: }
244: }
245: }
246: return map;
247: }
248:
249: /**
250: * @return a copy of the path
251: */
252: public Map<FactoryContainer, Attributes> getAllContainers() {
253: Map<FactoryContainer, Attributes> map = new LinkedHashMap<FactoryContainer, Attributes>(
254: _path.size());
255: synchronized (_path) {
256: for (Map.Entry<FactoryContainer, Attributes> entry : _path
257: .entrySet()) {
258: map.put(entry.getKey(),
259: new Attributes(entry.getValue()));
260: }
261: }
262: return map;
263: }
264:
265: }
|