| /******************************************************************************* |
| * Copyright (c) 2006 Oracle Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Oracle Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.bpel.validator.helpers; |
| |
| import java.io.BufferedReader; |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.FileNotFoundException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.io.PrintStream; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.Member; |
| import java.net.URL; |
| import java.util.Arrays; |
| import java.util.Comparator; |
| import java.util.HashSet; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.TreeSet; |
| |
| import org.eclipse.bpel.validator.model.ARule; |
| import org.eclipse.bpel.validator.model.IModelQueryLookups; |
| import org.eclipse.bpel.validator.model.INode; |
| import org.eclipse.bpel.validator.model.IProblem; |
| import org.eclipse.bpel.validator.model.Problem; |
| import org.eclipse.bpel.validator.model.RuleFactory; |
| import org.eclipse.bpel.validator.model.Runner; |
| import org.w3c.dom.Document; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| import org.xml.sax.InputSource; |
| |
| /** |
| * This is a skeleton of a validator that driver that only works with DOM document tree. |
| * Note that there is implementation for various IModelQuery lookups by using just the DOM |
| * of BPEL and WSDL and schema. |
| * |
| * So while this does run it does not produce correct results. |
| * |
| * |
| * @author Michal Chmielewski (michal.chmielewski@oracle.com) |
| * @date Jan 2, 2007 |
| * |
| */ |
| |
| @SuppressWarnings("nls") |
| |
| public class CmdValidator { |
| |
| static protected PrintStream OUT = System.out; |
| |
| static final protected IProblem[] EMPTY_RESULT = {}; |
| |
| protected Runner fRunner = null; |
| |
| /** |
| * Create a brand new |
| */ |
| @SuppressWarnings("unchecked") |
| public CmdValidator () { |
| |
| // |
| // register the rule factories for the validator. This is done via |
| |
| // the org.eclipse.bpel.validator.factories extension point in the plug-in. |
| |
| RuleFactory.INSTANCE.registerFactory( org.eclipse.bpel.validator.rules.Factory.INSTANCE ); |
| RuleFactory.INSTANCE.registerFactory( org.eclipse.bpel.validator.vprop.Factory.INSTANCE); |
| RuleFactory.INSTANCE.registerFactory( org.eclipse.bpel.validator.plt.Factory.INSTANCE); |
| RuleFactory.INSTANCE.registerFactory( org.eclipse.bpel.validator.wsdl.Factory.INSTANCE); |
| RuleFactory.INSTANCE.registerFactory( org.eclipse.bpel.validator.xpath.Factory.INSTANCE); |
| |
| // RuleFactory.INSTANCE.registerFactory( org.eclipse.bpel.validator.xpath0.Factory.INSTANCE); |
| // This just prints an error message for the "process" elements in an unrecognized namespace |
| RuleFactory.INSTANCE.registerFactory( org.eclipse.bpel.validator.unsupported.Factory.INSTANCE); |
| } |
| |
| /** |
| * Validate the given file. |
| * @param file |
| * @return the list of validation errors. |
| */ |
| |
| public IProblem[] validate (File file) { |
| // |
| //Step 1. Read the BPEL process using the Model API. |
| Element elm = null; |
| |
| try { |
| |
| LocationCapturingDOMParser parser = new LocationCapturingDOMParser(); |
| parser.parse( file.toString() ); |
| elm = parser.getDocument().getDocumentElement(); |
| |
| } catch (Exception ex) { |
| |
| OUT.printf("Error: Cannot read BPEL Process in %1$s", file); |
| ex.printStackTrace(OUT); |
| return EMPTY_RESULT; |
| |
| } |
| |
| if (elm == null) { |
| OUT.printf("Error: Cannot read BPEL Process in %1$s",file); |
| return EMPTY_RESULT; |
| } |
| // Step 2. Preparation for the validator. |
| |
| // Process as INode |
| INode node = ModelQueryImpl.getModelQuery().adapt(elm, INode.class,IModelQueryLookups.ADAPT_HINT_NONE); |
| |
| // Step 3. Run it |
| fRunner = new Runner ( ModelQueryImpl.getModelQuery(), node); |
| return fRunner.run(); |
| } |
| |
| |
| /** |
| * @param source |
| * @return a list of problems |
| */ |
| |
| public IProblem[] validate (URL source) { |
| // |
| //Step 1. Read the BPEL process using the Model API. |
| Element elm = null; |
| |
| try { |
| |
| LocationCapturingDOMParser parser = new LocationCapturingDOMParser(); |
| InputSource is = new InputSource(); |
| is.setPublicId(source.toString()); |
| is.setSystemId(source.toString()); |
| is.setByteStream( source.openStream() ); |
| parser.parse( is ); |
| elm = parser.getDocument().getDocumentElement(); |
| |
| } catch (Exception ex) { |
| |
| OUT.printf("Error: Cannot read BPEL Process in %1$s", source); |
| ex.printStackTrace(OUT); |
| return EMPTY_RESULT; |
| |
| } |
| |
| if (elm == null) { |
| OUT.printf("Error: Cannot read BPEL Process in %1$s",source); |
| return EMPTY_RESULT; |
| } |
| |
| // Process as INode |
| INode node = ModelQueryImpl.getModelQuery().adapt(elm, INode.class,IModelQueryLookups.ADAPT_HINT_NONE); |
| |
| // Step 3. Run it |
| fRunner = new Runner ( ModelQueryImpl.getModelQuery(), node); |
| return fRunner.run(); |
| } |
| |
| /** |
| * Log to a print stream |
| * @param problems |
| * @param ps |
| */ |
| |
| @SuppressWarnings("boxing") |
| public void log ( IProblem[] problems,PrintStream ps ) { |
| |
| ps.printf("<problems count=\"%1$d\">\n", problems.length); |
| |
| // Which SA-analysis cases are covered ? |
| if (fRunner != null) { |
| |
| Set<ARule> saChecks = new TreeSet<ARule>(new Comparator<ARule> ( ){ |
| public int compare(ARule o1, ARule o2) { |
| return o1.sa() - o2.sa(); |
| } |
| }); |
| |
| saChecks.addAll( fRunner.getSAChecks() ); |
| ps.printf(" <sa-cases>"); |
| for(ARule a : saChecks) { |
| ps.printf("%1$d,", a.sa() ); |
| } |
| ps.printf("0</sa-cases>\n"); |
| } |
| |
| // Step 5. Dump problems. |
| for(IProblem problem : problems) { |
| Map<String,Object> map = problem.getAttributes(); |
| ps.println(" <problem>"); |
| for(Map.Entry<String,Object> entry : map.entrySet()) { |
| Object value = entry.getValue(); |
| if (value == null) { |
| continue; |
| } |
| String v = toSafeXML(value); |
| if (value == null || "null".equals(v)) { |
| v = toSafeXML(value.toString()); |
| } |
| |
| ps.printf(" <%1$s>%2$s</%1$s>\n",entry.getKey(), v); |
| } |
| ps.println(" </problem>\n"); |
| } |
| ps.println("</problems>"); |
| // done. |
| } |
| |
| |
| @SuppressWarnings("boxing") |
| protected void logStats ( IProblem[] list, PrintStream ps ) { |
| int error = 0, warning = 0, info = 0, unknown = 0; |
| for(IProblem n : list) { |
| switch (n.getAttribute(IProblem.SEVERITY, -1)) { |
| case IProblem.SEVERITY_ERROR: |
| error ++; |
| break; |
| case IProblem.SEVERITY_WARNING: |
| warning ++; |
| break; |
| case IProblem.SEVERITY_INFO: |
| info ++; |
| break; |
| default : |
| unknown ++; |
| break; |
| } |
| } |
| ps.printf("%d errors, %d warnings, %d information\n", error,warning,info); |
| } |
| |
| protected String toSafeXML ( Object value ) { |
| if (value instanceof String) { |
| return toSafeXML ((String) value); |
| } |
| return toSafeXML(JavaScriptSource.getInstance().toSource(value)); |
| } |
| |
| |
| protected String toSafeXML ( String s) { |
| if (s.indexOf("&") >= 0) { |
| s = s.replaceAll("\\&", "&"); |
| } |
| if (s.indexOf("<") >= 0) { |
| s = s.replaceAll("\\<", "<"); |
| } |
| if (s.indexOf(">") >= 0) { |
| s = s.replaceAll("\\>", ">"); |
| } |
| return s; |
| } |
| |
| |
| |
| |
| |
| /** |
| * @param list |
| * @throws Exception |
| */ |
| |
| public void run (String ... list ) throws Exception { |
| |
| // process validation as before |
| for(String a : list ) { |
| |
| File aFile = new File(a); |
| |
| OUT.printf("Validating %1$s ...\n",aFile); |
| IProblem problems[] = validate (aFile); |
| |
| logStats(problems,OUT); |
| |
| if (problems.length == 0) { |
| continue; |
| } |
| |
| // Write the file which contains the current run errors |
| File log = new File(aFile + ".out.xml"); |
| OUT.printf(" - error list as XML to %1$s\n", log ); |
| PrintStream ps = null; |
| try { |
| ps = new PrintStream( log ); |
| log(problems, ps); |
| } catch (FileNotFoundException e) { |
| // |
| } finally { |
| if (ps != null) { |
| ps.close(); |
| } |
| } |
| |
| // write the log file which contains the source and superimposed on it |
| // we have the errors |
| log = new File(aFile + ".log"); |
| OUT.printf(" - log (xml source + errors) to %1$s\n", log ); |
| ps = null; |
| try { |
| ps = new PrintStream( log ); |
| errorListing(new FileInputStream(aFile) , problems, ps); |
| } catch (FileNotFoundException e) { |
| // |
| } finally { |
| if (ps != null) { |
| ps.close(); |
| } |
| } |
| |
| // |
| OUT.println(); |
| } |
| |
| } |
| |
| /** |
| * Do the actual run |
| * |
| * @param opt |
| * @throws Exception |
| */ |
| |
| public void run (GetOpt opt) throws Exception { |
| run (opt.parameters().toArray(EMPTY)); |
| } |
| |
| |
| static String [] EMPTY = {}; |
| |
| /** |
| * Main entry point for the command line validator. |
| * @param argv |
| * @throws Exception |
| */ |
| |
| |
| static public void main (String argv[]) throws Exception { |
| |
| CmdValidator builder = new CmdValidator(); |
| GetOpt opt = new GetOpt("-h",argv); |
| builder.run( opt ); |
| } |
| |
| |
| |
| /** |
| * Log to a print stream |
| * @param is the process definition (bpel) |
| * @param problems an array of problems |
| * @param ps the output stream to write to |
| * @throws Exception any exception that may be thrown. |
| */ |
| |
| @SuppressWarnings("boxing") |
| public void errorListing ( InputStream is, IProblem[] problems, PrintStream ps ) throws Exception { |
| |
| // sort the problems according to line number |
| Arrays.sort(problems, new Comparator<IProblem> () { |
| public int compare(IProblem o1, IProblem o2) { |
| return o1.getAttribute(IProblem.LINE_NUMBER,0) - o2.getAttribute(IProblem.LINE_NUMBER,0); |
| } |
| }); |
| |
| // TODO: Don't assume UTF-8; |
| BufferedReader br = new BufferedReader(new InputStreamReader( is,"UTF-8")); |
| |
| for(int lineNo = 1, index = 0; ; lineNo++) { |
| |
| String nextLine = br.readLine(); |
| if (nextLine == null) { |
| break; |
| } |
| ps.printf("%5d: %s\n",lineNo, nextLine ); |
| |
| for(;index < problems.length; index++) { |
| IProblem p = problems[index]; |
| int problemLineNo = p.getAttribute(IProblem.LINE_NUMBER,-1); |
| if (problemLineNo <= lineNo) { |
| // current line |
| ps.printf("%s: %s\n", severityOf ( p ), |
| p.getAttribute(IProblem.MESSAGE,"? Unknown ?")); |
| |
| ps.printf(" meta: rule=%s, sa=%s, msg.id=%s\n", p.getAttribute(IProblem.RULE), |
| p.getAttribute(IProblem.SA_CODE), p.getAttribute(IProblem.MESSAGE_ID)); |
| |
| String fix = p.getAttribute(IProblem.FIX, null); |
| |
| if (fix != null) { |
| ps.printf(" fix: %s\n", fix); |
| } |
| ps.println(); |
| } else { |
| break; |
| } |
| } |
| } |
| |
| br.close(); |
| ps.println(); |
| ps.println(); |
| logStats(problems, ps); |
| } |
| |
| |
| /** |
| * @param problem |
| * @return the severity string |
| */ |
| @SuppressWarnings("boxing") |
| public String severityOf ( IProblem problem ) { |
| int severity = problem.getAttribute( IProblem.SEVERITY,-1); |
| |
| switch (severity) { |
| case IProblem.SEVERITY_ERROR: |
| return "error"; |
| case IProblem.SEVERITY_INFO: |
| return "info"; |
| case IProblem.SEVERITY_WARNING: |
| return "warning"; |
| } |
| return "error"; |
| } |
| |
| |
| /** |
| * Reads the messages file into a problems array so that comparison of |
| * results can take place. |
| * |
| * @param aFile |
| * @return a list of problems. |
| * @throws Exception |
| */ |
| |
| |
| static public IProblem[] readMessages ( File aFile ) throws Exception { |
| return readMessages( new FileInputStream(aFile), aFile.getPath() ); |
| } |
| |
| |
| /** |
| * @param is |
| * @param id |
| * @return a list of problems. |
| * @throws Exception |
| */ |
| static public IProblem[] readMessages ( InputStream is , String id ) throws Exception { |
| |
| LocationCapturingDOMParser parser = new LocationCapturingDOMParser(); |
| |
| InputSource inputSource = new InputSource(); |
| inputSource.setByteStream(is); |
| inputSource.setPublicId(id); |
| inputSource.setSystemId(id); |
| parser.parse( inputSource ); |
| |
| Document doc = parser.getDocument() ; |
| |
| Element elm = doc.getDocumentElement(); |
| |
| if ("problems".equals (elm.getTagName()) == false) { |
| return EMPTY_RESULT; |
| } |
| |
| List<IProblem> list = new LinkedList<IProblem>(); |
| |
| NodeList nl = elm.getElementsByTagName("problem"); |
| |
| for(int i=0, j=nl.getLength(); i<j; i++) { |
| Element e = (Element) nl.item(i); |
| list.add( Element2Problem (e) ); |
| } |
| |
| return list.toArray(EMPTY_RESULT); |
| } |
| |
| static Set<String> KEY_SET = keys ( IProblem.class) ; |
| |
| |
| static IProblem Element2Problem ( Element e ) { |
| |
| IProblem p = new Problem (); |
| |
| Node n = e.getFirstChild(); |
| while (n != null) { |
| if (n instanceof Element) { |
| Element ne = (Element) n; |
| String key = ne.getTagName(); |
| if (KEY_SET.contains(key)) { |
| p.setAttribute(key, ne.getTextContent()); |
| } |
| } |
| n = n.getNextSibling(); |
| } |
| |
| return p; |
| } |
| |
| |
| static Set<String> keys ( Class<?> klazz ) { |
| |
| Set<String> set = new HashSet<String>(); |
| |
| for(Field f: klazz.getFields() ) { |
| int modifies = f.getModifiers(); |
| String name = f.getName(); |
| if (name.equals ( name.toUpperCase() ) == false) { |
| continue; |
| } |
| if ((modifies & Member.PUBLIC) != Member.PUBLIC ) { |
| continue; |
| } |
| if (f.getType() != String.class) { |
| continue; |
| } |
| |
| try { |
| String value = (String) f.get(null); |
| set.add( value ); |
| } catch (Throwable t) { |
| // should not happen. |
| } |
| } |
| |
| return set; |
| } |
| } |