001: /*
002: * Hammurapi
003: * Automated Java code review system.
004: * Copyright (C) 2004 Hammurapi Group
005: *
006: * This program is free software; you can redistribute it and/or modify
007: * it under the terms of the GNU General Public License as published by
008: * the Free Software Foundation; either version 2 of the License, or
009: * (at your option) any later version.
010: *
011: * This program is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
014: * GNU General Public License for more details.
015: *
016: * You should have received a copy of the GNU General Public License
017: * along with this program; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: *
020: * URL: http://www.hammurapi.org
021: * e-Mail: support@hammurapi.biz
022: */
023:
024: package org.hammurapi;
025:
026: import java.text.ParseException;
027: import java.text.SimpleDateFormat;
028: import java.util.Collection;
029: import java.util.Date;
030: import java.util.HashSet;
031: import java.util.Iterator;
032: import java.util.LinkedList;
033: import java.util.Set;
034:
035: import javax.xml.transform.TransformerException;
036:
037: import org.apache.oro.text.GlobCompiler;
038: import org.apache.oro.text.regex.MalformedPatternException;
039: import org.apache.oro.text.regex.Pattern;
040: import org.apache.oro.text.regex.Perl5Matcher;
041: import org.apache.xpath.CachedXPathAPI;
042: import org.w3c.dom.Element;
043: import org.w3c.dom.Node;
044: import org.w3c.dom.traversal.NodeIterator;
045:
046: import com.pavelvlasov.jsel.CompilationUnit;
047: import com.pavelvlasov.jsel.JselException;
048: import com.pavelvlasov.jsel.LanguageElement;
049: import com.pavelvlasov.jsel.Operation;
050: import com.pavelvlasov.jsel.Package;
051: import com.pavelvlasov.jsel.TypeBody;
052: import com.pavelvlasov.review.Signed;
053: import com.pavelvlasov.xml.dom.AbstractDomObject;
054:
055: /**
056: * @author Pavel Vlasov
057: * @version $Revision: 1.10 $
058: */
059: public class DomWaiver extends AbstractDomObject implements Waiver {
060: private Set signatures = new HashSet();
061: boolean active = true;
062: boolean hadSignatures = false;
063:
064: private LinkedList elements = new LinkedList();
065:
066: private static class ElementEntry {
067: boolean exclude;
068: String name;
069: String operationSignature;
070: Pattern fileNamePattern;
071: }
072:
073: /**
074: * @param parameter
075: * @param entry
076: */
077: private static void parseParameter(Object parameter,
078: ElementEntry entry) {
079: String value = (String) parameter;
080: int pi = value.indexOf('(');
081: if (pi == -1) {
082: entry.name = value;
083: } else {
084: int lastDot = value.lastIndexOf('.', pi);
085: if (lastDot == -1) {
086: entry.name = "*";
087: entry.operationSignature = value;
088: } else {
089: entry.name = value.substring(0, lastDot);
090: entry.operationSignature = value.substring(lastDot + 1);
091: }
092: }
093: }
094:
095: /**
096: * @param holder
097: */
098: public DomWaiver(Element holder) throws HammurapiException {
099: super ();
100: try {
101: CachedXPathAPI cxpa = new CachedXPathAPI();
102: inspectorName = getElementText(holder, "inspector-name",
103: cxpa);
104:
105: NodeIterator it = cxpa.selectNodeIterator(holder,
106: "signature");
107: Node signatureNode;
108: while ((signatureNode = it.nextNode()) != null) {
109: if (signatureNode instanceof Element) {
110: hadSignatures = true;
111: signatures.add(getElementText(signatureNode));
112:
113: }
114: }
115:
116: it = cxpa
117: .selectNodeIterator(holder,
118: "include-element|exclude-element|include-file|exclude-file");
119: Element element;
120: while ((element = (Element) it.nextNode()) != null) {
121: String elementText = getElementText(element);
122: if ("include-element".equals(element.getNodeName())) {
123: ElementEntry entry = new ElementEntry();
124: entry.exclude = false;
125: parseParameter(elementText, entry);
126: elements.addFirst(entry);
127: } else if ("exclude-element".equals(element
128: .getNodeName())) {
129: ElementEntry entry = new ElementEntry();
130: entry.exclude = true;
131: parseParameter(elementText, entry);
132: elements.addFirst(entry);
133: } else if ("include-file".equals(element.getNodeName())) {
134: GlobCompiler compiler = new GlobCompiler();
135: ElementEntry entry = new ElementEntry();
136: entry.exclude = false;
137: try {
138: entry.fileNamePattern = compiler
139: .compile(elementText);
140: } catch (MalformedPatternException e) {
141: throw new HammurapiException(e);
142: }
143: elements.addFirst(entry);
144: } else if ("exclude-file".equals(element.getNodeName())) {
145: GlobCompiler compiler = new GlobCompiler();
146: ElementEntry entry = new ElementEntry();
147: entry.exclude = true;
148: try {
149: entry.fileNamePattern = compiler
150: .compile(elementText);
151: } catch (MalformedPatternException e) {
152: throw new HammurapiException(e);
153: }
154: elements.addFirst(entry);
155: }
156: }
157:
158: reason = getElementText(holder, "reason", cxpa);
159:
160: String expirationDateVal = getElementText(holder,
161: "expiration-date", cxpa);
162: if (expirationDateVal != null) {
163: SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
164: expirationDate = sdf.parse(expirationDateVal);
165: }
166: } catch (TransformerException e) {
167: throw new HammurapiException(e);
168: } catch (ParseException e) {
169: throw new HammurapiException(e);
170: }
171: }
172:
173: private String inspectorName;
174:
175: public String getInspectorName() {
176: return inspectorName;
177: }
178:
179: private Date expirationDate;
180:
181: public Date getExpirationDate() {
182: return expirationDate;
183: }
184:
185: private String reason;
186:
187: public String getReason() {
188: return reason;
189: }
190:
191: public boolean waive(Violation violation, boolean peek) {
192: if (inspectorName.equals(violation.getDescriptor().getName())) {
193: if (hadSignatures) {
194: if (violation.getSource() instanceof Signed) {
195: String signature = ((Signed) violation.getSource())
196: .getSignature();
197: if (signatures.contains(signature)) {
198: if (!peek) {
199: signatures.remove(signature);
200: }
201: active = !signatures.isEmpty();
202: return true;
203: }
204: }
205: }
206:
207: if (elements.isEmpty()) {
208: return true;
209: }
210:
211: if (violation.getSource() instanceof LanguageElement) {
212: for (LanguageElement element = (LanguageElement) violation
213: .getSource(); element != null; element = element
214: .getParent()) {
215: if (_waive(element)) {
216: return true;
217: }
218: }
219:
220: if (_waive(((LanguageElement) violation.getSource())
221: .getCompilationUnit().getPackage())) {
222: return true;
223: }
224: } else if (violation.getSource() instanceof com.pavelvlasov.jsel.Package) {
225: if (_waive(violation.getSource())) {
226: return true;
227: }
228: }
229: }
230: return false;
231: }
232:
233: private Perl5Matcher matcher = new Perl5Matcher();
234:
235: /**
236: * @param source
237: */
238: private boolean _waive(Object o) {
239: if (o instanceof Package) {
240: Iterator it = elements.iterator();
241: while (it.hasNext()) {
242: ElementEntry entry = (ElementEntry) it.next();
243: Package pkg = (Package) o;
244: if (entry.name != null
245: && entry.operationSignature == null
246: && ("*".equals(entry.name)
247: || pkg.getName().equals(entry.name) || (entry.name
248: .endsWith(".*") && pkg
249: .getName()
250: .startsWith(
251: entry.name
252: .substring(
253: 0,
254: entry.name
255: .length() - 2))))) {
256: return !entry.exclude;
257: }
258: }
259: } else if (o instanceof CompilationUnit) {
260: Iterator it = elements.iterator();
261: while (it.hasNext()) {
262: ElementEntry entry = (ElementEntry) it.next();
263: if (entry.fileNamePattern != null
264: && matcher.matches(((CompilationUnit) o)
265: .getName(), entry.fileNamePattern)) {
266: return !entry.exclude;
267: }
268: }
269: } else if (o instanceof TypeBody) {
270: // only if package included ???
271: Iterator it = elements.iterator();
272: while (it.hasNext()) {
273: ElementEntry entry = (ElementEntry) it.next();
274: try {
275: TypeBody typeBody = (TypeBody) o;
276: if (entry.name != null
277: && entry.operationSignature == null
278: && typeBody.isKindOf(entry.name)) {
279: return !entry.exclude;
280: }
281: } catch (JselException e) {
282: if (!(e.getCause() instanceof ClassNotFoundException)) {
283: return false;
284: }
285: }
286: }
287: } else if (o instanceof Operation) {
288: // only if type included ???
289: Iterator it = elements.iterator();
290: while (it.hasNext()) {
291: ElementEntry entry = (ElementEntry) it.next();
292: try {
293: Operation operation = (Operation) o;
294: if (entry.name != null
295: && entry.operationSignature != null
296: && ("*".equals(entry.name) || operation
297: .getEnclosingType().isKindOf(
298: entry.name))
299: && operation.getInfo()
300: .isArgumentCompatible(
301: entry.operationSignature)) {
302: return !entry.exclude;
303: }
304: } catch (JselException e) {
305: throw new HammurapiRuntimeException(e);
306: }
307: }
308: }
309:
310: return false;
311: }
312:
313: public boolean isActive() {
314: return active;
315: }
316:
317: public Collection getSignatures() {
318: return signatures;
319: }
320:
321: }
|