poi-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kiwiwi...@apache.org
Subject svn commit: r1857518 [2/7] - in /xmlbeans/branches/xmlbeans-536: ./ src/jam/ src/jam/org/ src/jam/org/apache/ src/jam/org/apache/xmlbeans/ src/jam/org/apache/xmlbeans/impl/ src/jam/org/apache/xmlbeans/impl/jam/ src/jam/org/apache/xmlbeans/impl/jam/anno...
Date Sun, 14 Apr 2019 13:55:07 GMT
Added: xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/JamService.java
URL: http://svn.apache.org/viewvc/xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/JamService.java?rev=1857518&view=auto
==============================================================================
--- xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/JamService.java (added)
+++ xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/JamService.java Sun Apr 14 13:55:06 2019
@@ -0,0 +1,65 @@
+/*   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.xmlbeans.impl.jam;
+
+
+
+/**
+ * <p>Encapsulates the a set of java classes which were which met a set of
+ * criteria described in a JamServiceParams object.  A JamService exposes both a
+ * particular set of JClasses, as well as a JamClassLoader which can be used
+ * to load related classes.</p>
+ *
+ * @author Patrick Calahan &lt;email: pcal-at-bea-dot-com&gt;
+ */
+public interface JamService {
+
+  /**
+   * Returns a JamClassLoader which can be used to load JClasses from class-
+   * and source-file locations specified in the JamServiceParams with which
+   * this service was instantiated.  Note that it is possible to use this
+   * mechanism to load JClasses that are not returned by getClasses().
+   */
+  public JamClassLoader getClassLoader();
+
+  /**
+   * Returns the names of the classes that were described in the
+   * JamServiceParams object used to create this service.  Note that this
+   * list will never change for a given service; though it is possible
+   * to use the service's JamClassLoader to load other types, this method will
+   * always return the initial set of classes.
+   */
+  public String[] getClassNames();
+
+  /**
+   * Returns an iterator of the JClasses named in the array returned by
+   * getClassNames().
+   */
+  public JamClassIterator getClasses();
+
+  /**
+   * Returns all of the JClasses returned by getClasses() in a single
+   * array.  Use of this method (as opposed to getClasses()) is not advised
+   * if you expect to be dealing with a very large set of classes, as it makes
+   * it less likely that JClasses will be garbage collected when no longer
+   * needed.
+   */
+  public JClass[] getAllClasses();
+
+  //public void invalidate(JClass clazz);
+
+  //public void invalidateAll();
+}

Added: xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/JamServiceFactory.java
URL: http://svn.apache.org/viewvc/xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/JamServiceFactory.java?rev=1857518&view=auto
==============================================================================
--- xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/JamServiceFactory.java (added)
+++ xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/JamServiceFactory.java Sun Apr 14 13:55:06 2019
@@ -0,0 +1,122 @@
+/*   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.xmlbeans.impl.jam;
+
+import org.apache.xmlbeans.impl.jam.internal.JamPrinter;
+import org.apache.xmlbeans.impl.jam.provider.JamServiceFactoryImpl;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+/**
+ * Start here!  This is the normal entry point into the JAM subsystem.
+ * JamServiceFactory is a singleton factory which can create a new
+ * JamServiceParams and JServices.  Here is a code sample that demonstrates
+ * how to use JamServiceFactory.
+ *
+ * <pre>
+ * // Get the factory singleton
+ * JamServiceFactory factory = JamServiceFactory.getInstance();
+ *
+ * // Use the factory to create an object that we can use to specify what
+ * // java types we want to view
+ * JamServiceParams params = factory.createServiceParams();
+ *
+ * // Include the classes under mypackage
+ * params.includeSources(new File("c:/myproject/src","mypackage/*.java"));
+ *
+ * // Create a JamService, which will contain JClasses for the classes found in mypackage
+ * JamService service = factory.createServiceRoot(params);
+ * </pre>
+ *
+ * @author Patrick Calahan &lt;email: pcal-at-bea-dot-com&gt;
+ */
+public abstract class JamServiceFactory {
+
+  // ========================================================================
+  // Constants
+
+  private static final JamServiceFactory DEFAULT = new JamServiceFactoryImpl();
+
+  // ========================================================================
+  // Singleton
+
+  /**
+   * Return the default factory singleton for this VM.
+   */
+  public static JamServiceFactory getInstance() { return DEFAULT; }
+
+  // ========================================================================
+  // Constructors
+
+  protected JamServiceFactory() {}
+
+  // ========================================================================
+  // Public methods
+
+  /**
+   * Create a new JamServiceParams instance.  The params can be populated
+   * and then given to the createServiceRoot method to create a new JamService.
+   */
+  public abstract JamServiceParams createServiceParams();
+
+  /**
+   * Create a new JamService from the given parameters.
+   *
+   * @throws IOException if an IO error occurred while creating the service
+   * @throws IllegalArgumentException if the params is null or not
+   * an instance returned by createServiceParams().
+   */
+  public abstract JamService createService(JamServiceParams params) throws IOException;
+
+  /**
+   * <p>Returns a new JamClassLoader which simply wraps the system
+   * classloader.</p>
+   */
+  public abstract JamClassLoader createSystemJamClassLoader();
+
+  /**
+   * <p>Returns a new JamClassLoader which simply wraps the given
+   * classloader.</p>
+   */
+  public abstract JamClassLoader createJamClassLoader(ClassLoader cl);
+
+  // ========================================================================
+  // main() method
+
+  public static void main(String[] args) {
+    try {
+      JamServiceParams sp = getInstance().createServiceParams();
+      for(int i=0; i<args.length; i++) {
+        sp.includeSourcePattern(new File[] {new File(".")},args[i]);
+      }
+      JamService service = getInstance().createService(sp);
+      JamPrinter jp = JamPrinter.newInstance();
+      PrintWriter out = new PrintWriter(System.out);
+      for(JamClassIterator i = service.getClasses(); i.hasNext(); ) {
+        out.println("-------- ");
+        jp.print(i.nextClass(),out);
+      }
+      out.flush();
+    } catch(Exception e){
+      e.printStackTrace();
+    }
+    System.out.flush();
+    System.err.flush();
+
+  }
+}

Added: xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/JamServiceParams.java
URL: http://svn.apache.org/viewvc/xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/JamServiceParams.java?rev=1857518&view=auto
==============================================================================
--- xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/JamServiceParams.java (added)
+++ xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/JamServiceParams.java Sun Apr 14 13:55:06 2019
@@ -0,0 +1,288 @@
+/*   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.xmlbeans.impl.jam;
+
+import org.apache.xmlbeans.impl.jam.annotation.JavadocTagParser;
+import org.apache.xmlbeans.impl.jam.provider.JamClassBuilder;
+import org.apache.xmlbeans.impl.jam.provider.JamLogger;
+import org.apache.xmlbeans.impl.jam.visitor.MVisitor;
+
+import java.io.File;
+import java.io.PrintWriter;
+
+/**
+ * <p>Used to specify the parameters with which a JamService will be
+ * created.</p>
+ *
+ * @author Patrick Calahan &lt;email: pcal-at-bea-dot-com&gt;
+ */
+public interface JamServiceParams {
+
+  // ========================================================================
+  // Public methods
+
+  /**
+   * <p>Include a single java source file to be viewed.  Note that if your
+   * code is able to understand the file/package structure in which the
+   * source exists, you may get better performance by using the various
+   * include... methods which take a sourcepath parameter.</p>
+   */
+  public void includeSourceFile(File file);
+
+  /**
+   * Specifies a set of java source files to be included in the JamService.
+   *
+   * <p>Note that calling this method implicitly includes the 'root' in
+   * the sourcepath (exactly as if addSourcepath(root) had been called).</p>
+   *
+   * @param sourcepath Root directory/ies containing source files.
+   * @param pattern A relative file pattern (as described above under
+   * 'Include and Exclude Patterns').
+   * @throws IllegalArgumentException if either argument is null.
+   */
+  public void includeSourcePattern(File[] sourcepath, String pattern);
+
+  /**
+   * Specifies a set of java source files to be excluded in the JamService.
+   * Note that calling this method implicitly includes the 'sourcepath' in
+   * the sourcepath (as in a call to addSourcepath(sourcepath)).
+   *
+   * @param sourcepath Root directory of the source files.
+   * @param pattern A relative file pattern (as described above under
+   * 'Include and Exclude Patterns').
+   * @throws IllegalArgumentException if either argument is null.
+   */
+  public void excludeSourcePattern(File[] sourcepath, String pattern);
+
+  /**
+   * Specifies a set of java class files to be excluded in the JamService.
+   * Note that calling this method implicitly includes the 'classpath' in
+   * the classpath (as in a call to addClasspath(classpath)).
+   *
+   * @param classpath Root directory of the source files.
+   * @param pattern A relative file pattern (as described above under
+   * 'Include and Exclude Patterns').
+   * @throws IllegalArgumentException if either argument is null.
+   */
+  public void includeClassPattern(File[] classpath, String pattern);
+
+  /**
+   * Specifies a set of java class files to be excluded from the JamService.
+   * Note that calling this method implicitly includes the 'classpath' in
+   * the classpath (as in a call to addClasspath(classpath)).
+   *
+   * @param classpath Root directory of the source files.
+   * @param pattern A relative file pattern (as described above under
+   * 'Include and Exclude Patterns').
+   * @throws IllegalArgumentException if either argument is null.
+   */
+  public void excludeClassPattern(File[] classpath, String pattern);
+
+  /**
+   * <p>Includes a single source File in the JamService.  The sourcepath parameter
+   * should identify the source sourcepath of the java source file; the sourceFile
+   * parameter must be under the sourcepath subtree.</p>
+   *
+   * <p>For example, if a class "foo.bar.MyClass" is stored in a file
+   * "c:/myproject/src/foo/bar/MyClass.java", that class could be included in
+   * the service by calling</p>
+   *
+   * <pre>
+   *  includeSourceFile(new File("c:/myproject/src"),
+   *                    new File("c:/myproject/src/foo/bar/MyClass.java"));
+   * </pre>
+   *
+   * <p>Note that this equivalent to calling</p>
+   *
+   * <pre>
+   *  includeSourceFiles(new File("c:/myproject/src"),"foo/bar/MyClass.java");
+   * </pre>
+   *
+   * <p>If you are calling this method and have more than one sourcepath directory,
+   * and do not readily know which is the correct sourcepath for a given source
+   * File, you can use the getRootForFile() utility method to determine the
+   * correct sourcepath to use.</p>
+   *
+   * <p>Note that calling this method implicitly includes the 'sourcepath' in
+   * the sourcepath (exactly as if addSourcepath(sourcepath) had been called).</p>
+   *
+   * @param sourcepath source sourcepath for the java source file
+   * @param sourceFile the java source file
+   * @throws IllegalArgumentException if either argument is null or if
+   * sourcepath is not an ancestor of sourceFile in the file system.
+   */
+  public void includeSourceFile(File[] sourcepath, File sourceFile);
+
+  /**
+   * <p>Excludes a single source File in the JamService in exactly the same
+   * way theat includeSourceFile() includes a source file.
+   */
+  public void excludeSourceFile(File[] sourcepath, File sourceFile);
+
+  /**
+   * <p>Includes a single class File in the JamService in exactly the same
+   * way theat includeSourceFile() includes a source file.
+   */
+  public void includeClassFile(File[] sourcepath, File sourceFile);
+
+  /**
+   * <p>Excludes a single class File in the JamService in exactly the same
+   * way theat includeSourceFile() includes a source file.
+   */
+  public void excludeClassFile(File[] sourcepath, File sourceFile);
+
+  /**
+   * Names a specific class to be included in the JamService.  Note that
+   * this will return an 'unresolved' JClass unless a source or class file
+   * for the named class is available in the classpath or sourcepath.
+   *
+   * @param qualifiedClassname a full-qualified classname
+   * @throws IllegalArgumentException if the argument is null or not
+   * a valid classname.
+   */
+  public void includeClass(String qualifiedClassname);
+
+
+  /**
+   * Names a specific class to be excluded in the JamService.  Note that
+   * this will have no affect if the named class cannot be found in the
+   * sourcepath or classpath.
+   *
+   * @param qualifiedClassname a full-qualified classname
+   * @throws IllegalArgumentException if the argument is null or not
+   * a valid classname.
+   */
+  public void excludeClass(String qualifiedClassname);
+
+  /**
+   * Adds an elements to the JamService sourcepath.  The service's JamClassLoader
+   * will search this path to find a .java file on which to base a JClass
+   * when requested to load a class that was not included in the service.
+   */
+  public void addSourcepath(File sourcepathElement);
+
+  /**
+   * Adds an elements to the JamService classpath.  The service's JamClassLoader
+   * will search this path to find a .class file on which to base a JClass
+   * when requested to load a class that was not included in the service
+   * and for which no source could be found in the sourcepath.
+   *
+   * @param classpathElement elements of the classpath
+   * @throws IllegalArgumentException if the argument is null
+   */
+  public void addClasspath(File classpathElement);
+
+  /**
+   * Sets a PrintWriter to which the JamService implementation should log
+   * errors and debugging information.  If this is never set, all such output
+   * will be suppressed.
+   *
+   * @param out a PrintWriter to write to
+   * @throws IllegalArgumentException if the argument is null
+   */
+  public void setLoggerWriter(PrintWriter out);
+
+  /**
+   * Sets the JamLogger which will receive error and warning messages from
+   * JAM.
+   */ 
+  public void setJamLogger(JamLogger logger);
+
+  /**
+   * </p>Enables verbose debugging output from all instances of the given
+   * class.</p>
+   */
+  public void setVerbose(Class c);
+
+
+  /**
+   * <p>Enables or suppresses the logging of warning messages.  By default
+   * this is true.</p>
+   */
+  public void setShowWarnings(boolean b);
+
+  /**
+   * Sets the parent JamClassLoader of the service JamClassLoader.
+   *
+   * @param loader the parent loaer
+   * @throws IllegalArgumentException if the argument is null
+   */
+  public void setParentClassLoader(JamClassLoader loader);
+
+  /**
+   * <p>Adds an elements to the tool classpath.  This is the classpath that
+   * will be used by the JamService implementation to find any libraries
+   * on which it depends.  This classpath is distinct from the service
+   * classpath set by addClasspath() in that it has no affect on the input
+   * class set - it's only used for finding classes on which JAM
+   * itself depends.</p>
+   *
+   * @param classpathElement elements of the classpath
+   * @throws IllegalArgumentException if the argument is null
+   */
+  public void addToolClasspath(File classpathElement);
+
+  //DOCME
+  public void setPropertyInitializer(MVisitor initializer);
+
+  //DOCME
+  public void addInitializer(MVisitor initializer);
+
+  //DOCME
+  public void setJavadocTagParser(JavadocTagParser tp);
+
+  /**
+   * <p>Specifies whether the JAM Service should load classes from the system
+   * classpath.  The default for this is true, and you shouldn't set it to
+   * false unless you really know what you are doing.</p>
+   */
+  public void setUseSystemClasspath(boolean use);
+
+  /**
+   * <p>Adds a custom JamClassBuilder which will be consulted by the
+   * JamClassLoader when constructing representation of java types.  The given
+   * class builder will have priority over priority over JAM's default
+   * source- and reflection-based ClassBuilders.  If this method id
+   * called more than once, the extra class builders will be prioritized
+   * in the order in which they were added.</p>
+   */
+  public void addClassBuilder(JamClassBuilder cb);
+
+  /**
+   * DOCME
+   */
+  public void addClassLoader(ClassLoader cl);
+
+  /**
+   * <p>Sets an implementation-specific property.</p>
+   */
+  public void setProperty(String name, String value);
+
+  /**
+   * <p>Sets whether warnings should be displayed when running under
+   * JDK 1.4.  The default is true.</p>
+   */ 
+  public void set14WarningsEnabled(boolean b);
+
+  /**
+   * @deprecated use setVerbose(Class).  This is the same as
+   * setVerbose(Object.class).
+   */
+  public void setVerbose(boolean v);
+
+
+
+}
\ No newline at end of file

Added: xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/JamUtils.java
URL: http://svn.apache.org/viewvc/xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/JamUtils.java?rev=1857518&view=auto
==============================================================================
--- xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/JamUtils.java (added)
+++ xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/JamUtils.java Sun Apr 14 13:55:06 2019
@@ -0,0 +1,161 @@
+/*   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.xmlbeans.impl.jam;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Comparator;
+
+/**
+ * <p>Singleton collection of utility methods which can be very useful in
+ * some samples, but not often enough to warrant inclusion in the main
+ * APIs.  </p>
+ *
+ * <p>Most of these are here to help you jump from the JClass
+ * hierarchy to the java.lang.reflect hierarchy.  This is primarily
+ * useful when you find yourself, for example, wanting to actually invoke
+ * a method represented by a JMethod.</p>
+ *
+ * @author Patrick Calahan &lt;email: pcal-at-bea-dot-com&gt;
+ */
+public class JamUtils {
+
+  // ========================================================================
+  // Singleton
+
+  public static final JamUtils getInstance() { return INSTANCE; }
+
+  private JamUtils() {}
+
+  private static final JamUtils INSTANCE = new JamUtils();
+
+
+  // ========================================================================
+  // Public methods
+
+  /**
+   * <p>Returns the java.lang.Method on a given
+   * java.lang.Class which is represented by a given JMethod.</p>
+   *
+   * @param containedin Class to be searched for the method.
+   * @return
+   * @throws ClassNotFoundException if one of the paramType classes specified
+   * for this MethodName cannot be loaded from the given class' classloader.
+   * @throws NoSuchMethodException If the named method does not exist on
+   * this class.
+   * @throws IllegalArgumentException if any argument is null
+   */
+  public Method getMethodOn(JMethod method, Class containedin)
+    throws NoSuchMethodException, ClassNotFoundException
+  {
+    if (containedin == null) throw new IllegalArgumentException("null class");
+    if (method == null) throw new IllegalArgumentException("null method");
+    Class[] types = null;
+    JParameter[] params = method.getParameters();
+    if (params != null && params.length > 0) {
+      types = new Class[params.length];
+      for (int i = 0; i < types.length; i++) {
+        types[i] = loadClass(params[i].getType(),containedin.getClassLoader());
+      }
+    }
+    return containedin.getMethod(method.getSimpleName(), types);
+  }
+
+  /**
+   * <p>Returns the java.lang.Method on a given
+   * java.lang.Class which is represented by a given JMethod.</p>
+   *
+   * @param containedin Class to be searched for the ctor.
+   * @return
+   * @throws ClassNotFoundException if one of the paramType classes specified
+   * for this MethodName cannot be loaded from the given class' classloader.
+   * @throws NoSuchMethodException If the named ctor does not exist on
+   * this class.
+   * @throws IllegalArgumentException if any argument is null
+   */
+  public Constructor getConstructorOn(JConstructor ctor, Class containedin)
+    throws NoSuchMethodException, ClassNotFoundException
+  {
+    if (containedin == null) throw new IllegalArgumentException("null class");
+    if (ctor == null) throw new IllegalArgumentException("null ctor");
+    Class[] types = null;
+    JParameter[] params = ctor.getParameters();
+    if (params != null && params.length > 0) {
+      types = new Class[params.length];
+      for (int i = 0; i < types.length; i++) {
+        types[i] = loadClass(params[i].getType(),containedin.getClassLoader());
+      }
+    }
+    return containedin.getConstructor(types);
+  }
+
+  /**
+   * <p>Returns the java.lang.Method on a given
+   * java.lang.Class which is represented by a given JMethod.</p>
+   *
+   * @param containedin Class to be searched for the method.
+   * @return
+   * @throws NoSuchFieldException if the field does not exist on the class.
+   * @throws IllegalArgumentException if any argument is null
+   */
+  public Field getFieldOn(JField field, Class containedin)
+    throws NoSuchFieldException
+  {
+    if (containedin == null) throw new IllegalArgumentException("null class");
+    if (field == null) throw new IllegalArgumentException("null field");
+    return containedin.getField(field.getSimpleName());
+  }
+
+
+  /**
+   * <p>Loads the java.lang.Class represented by a given JClass out of a given
+   * classloader.</p>
+   * @return
+   * @throws ClassNotFoundException If the class is not found in the classloader
+   */
+  public Class loadClass(JClass clazz, ClassLoader inThisClassloader)
+    throws ClassNotFoundException
+  {
+    return inThisClassloader.loadClass(clazz.getQualifiedName());
+  }
+
+  /**
+   * Sorts the given array in place so that the elements are ordered by
+   * their sourcePosition's line numbers.
+   */
+  public void placeInSourceOrder(JElement[] elements) {
+    if (elements == null) throw new IllegalArgumentException("null elements");
+    Arrays.sort(elements,SOURCE_POSITION_COMPARATOR);
+  }
+
+  // ========================================================================
+  // Private
+
+  private static Comparator SOURCE_POSITION_COMPARATOR = new Comparator() {
+
+    public int compare(Object o, Object o1) {
+      JSourcePosition p1 = ((JElement)o).getSourcePosition();
+      JSourcePosition p2 = ((JElement)o1).getSourcePosition();
+      if (p1 == null) return (p2 == null) ? 0 : -1;
+      if (p2 == null) return 1;
+      return (p1.getLine() < p2.getLine()) ? -1 :
+        (p1.getLine() > p2.getLine()) ? 1 : 0;
+    }
+  };
+
+
+}
\ No newline at end of file

Added: xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/annotation/AnnotationProxy.java
URL: http://svn.apache.org/viewvc/xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/annotation/AnnotationProxy.java?rev=1857518&view=auto
==============================================================================
--- xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/annotation/AnnotationProxy.java (added)
+++ xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/annotation/AnnotationProxy.java Sun Apr 14 13:55:06 2019
@@ -0,0 +1,103 @@
+/*   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.xmlbeans.impl.jam.annotation;
+
+import org.apache.xmlbeans.impl.jam.JAnnotationValue;
+import org.apache.xmlbeans.impl.jam.JClass;
+import org.apache.xmlbeans.impl.jam.provider.JamLogger;
+import org.apache.xmlbeans.impl.jam.provider.JamServiceContext;
+
+/**
+ * <p>Provides a proxied view of some annotation artifact.  JAM calls the
+ * public methods on this class to initialize the proxy with annotation
+ * values; those methods should not be called by user code.</p>
+ *
+ * @author Patrick Calahan &lt;email: pcal-at-bea-dot-com&gt;
+ */
+/**
+ * @deprecated do not use, moving into internal
+ */
+public abstract class AnnotationProxy {
+
+  // ========================================================================
+  // Constants
+
+  /**
+   * <p>Name of the member of annotations which have only a single member.
+   * As specified in JSR175, that name is "value", but you should use
+   * this constant to prevent typos.</p>
+   */
+  public static final String SINGLE_MEMBER_NAME = "value";
+
+
+  /**
+   * <p>The delimiters to use by default when parsing out name=value pairs
+   * from a javadoc tag.</p>
+   */
+  private static final String DEFAULT_NVPAIR_DELIMS = "\n\r";
+
+  // ========================================================================
+  // Variables
+
+  protected JamServiceContext mContext;
+
+  // ========================================================================
+  // Initialization methods - called by JAM, don't implement
+
+  /**
+   * <p>Called by JAM to initialize the proxy.  Do not try to call this
+   * yourself.</p>
+   */
+  public void init(JamServiceContext ctx) {
+    if (ctx == null) throw new IllegalArgumentException("null logger");
+    mContext = ctx;
+  }
+
+  // ========================================================================
+  // Public abstract methods
+
+  /**
+   * <p>Called by JAM to initialize a named member on this annotation proxy.
+   * </p>
+   */
+  public abstract void setValue(String name, Object value, JClass type);
+
+  //docme
+  public abstract JAnnotationValue[] getValues();
+
+
+  //docme
+  public JAnnotationValue getValue(String named) {
+    if (named == null) throw new IllegalArgumentException("null name");
+    //FIXME this impl is very gross
+    named = named.trim();
+    JAnnotationValue[] values = getValues();
+    for(int i=0; i<values.length; i++) {
+      
+      if (named.equals(values[i].getName())) return values[i];
+    }
+    return null;
+  }
+
+  // ========================================================================
+  // Protected methods
+
+  /**
+   * <p>Returns an instance of JamLogger that this AnnotationProxy should use
+   * for logging debug and error messages.</p>
+   */
+  protected JamLogger getLogger() { return mContext.getLogger(); }
+
+}
\ No newline at end of file

Added: xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/annotation/DefaultAnnotationProxy.java
URL: http://svn.apache.org/viewvc/xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/annotation/DefaultAnnotationProxy.java?rev=1857518&view=auto
==============================================================================
--- xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/annotation/DefaultAnnotationProxy.java (added)
+++ xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/annotation/DefaultAnnotationProxy.java Sun Apr 14 13:55:06 2019
@@ -0,0 +1,75 @@
+/*   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.xmlbeans.impl.jam.annotation;
+
+import org.apache.xmlbeans.impl.jam.JAnnotationValue;
+import org.apache.xmlbeans.impl.jam.JClass;
+import org.apache.xmlbeans.impl.jam.internal.elements.AnnotationValueImpl;
+import org.apache.xmlbeans.impl.jam.internal.elements.ElementContext;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * <p>Implementation of AnnotationProxy which is used when no user-defined
+ * type has been registered for a given annotation..  All it does is stuff
+ * values into a ValueMap.  Note that it inherits all of the default tag and
+ * annotation processing behaviors from AnnotationProxy.</p>
+ *
+ *
+ * @author Patrick Calahan &lt;email: pcal-at-bea-dot-com&gt;
+ */
+/**
+ * @deprecated do not use, moving into internal
+ */
+public class DefaultAnnotationProxy extends AnnotationProxy {
+
+  // ========================================================================
+  // Variables
+
+  private List mValues = new ArrayList();
+
+  // ========================================================================
+  // Constructors
+
+  public DefaultAnnotationProxy() {}
+
+  // ========================================================================
+  // Public methods
+
+  public JAnnotationValue[] getValues() {
+    JAnnotationValue[] out = new JAnnotationValue[mValues.size()];
+    mValues.toArray(out);
+    return out;
+  }
+
+  // ========================================================================
+  // TypedAnnotationProxyBase implementation
+
+  /**
+   * <p>Overrides this behavior to simply stuff the value into our
+   * annotation map.  The super class' implementation would try to
+   * find a bunch of setters that we don't have.</p>
+   */
+  public void setValue(String name, Object value, JClass type) {
+    if (name == null) throw new IllegalArgumentException("null name");
+    if (type == null) throw new IllegalArgumentException("null type");
+    if (value == null) throw new IllegalArgumentException("null value");
+    name = name.trim();
+    mValues.add(new AnnotationValueImpl((ElementContext)getLogger(),//yikes, nasty.  FIXME
+                                        name,value,type));
+  }
+}
+

Added: xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/annotation/JavadocTagParser.java
URL: http://svn.apache.org/viewvc/xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/annotation/JavadocTagParser.java?rev=1857518&view=auto
==============================================================================
--- xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/annotation/JavadocTagParser.java (added)
+++ xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/annotation/JavadocTagParser.java Sun Apr 14 13:55:06 2019
@@ -0,0 +1,139 @@
+/*   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.xmlbeans.impl.jam.annotation;
+
+import com.sun.javadoc.SourcePosition;
+import com.sun.javadoc.Tag;
+import org.apache.xmlbeans.impl.jam.JAnnotation;
+import org.apache.xmlbeans.impl.jam.JClass;
+import org.apache.xmlbeans.impl.jam.internal.elements.ElementContext;
+import org.apache.xmlbeans.impl.jam.mutable.MAnnotatedElement;
+import org.apache.xmlbeans.impl.jam.mutable.MAnnotation;
+import org.apache.xmlbeans.impl.jam.mutable.MSourcePosition;
+import org.apache.xmlbeans.impl.jam.provider.JamLogger;
+import org.apache.xmlbeans.impl.jam.provider.JamServiceContext;
+
+/**
+ * @author Patrick Calahan &lt;email: pcal-at-bea-dot-com&gt;
+ */
+public abstract class JavadocTagParser {
+
+  // ========================================================================
+  // Variables
+
+  private JamServiceContext mContext = null;
+  private boolean mAddSingleValueMembers = false;
+
+  // ========================================================================
+  // Public methods
+
+  /**
+   * <p>If true, all annotations will be given a single-member value whose
+   * value is the full raw contents of the javadoc tag.  The name of this
+   * member is JAnnotation.SINGLE_MEMBER_VALUE, or 'value'.  Note that this
+   * member will be overrdden in the event that the tag contains an
+   * explicit value named 'value'.</p>
+   *
+   * <p>The default for this setting is false.</p>
+   *
+   * @param b
+   */
+  public void setAddSingleValueMembers(boolean b) {
+    mAddSingleValueMembers = b;
+  }
+
+  /**
+   * <p>Called by JAM to initialize the proxy.  Do not try to call this
+   * yourself.</p>
+   */
+  public void init(JamServiceContext ctx) {
+    if (ctx == null) throw new IllegalArgumentException("null logger");
+    if (mContext != null) throw new IllegalStateException
+      ("JavadocTagParser.init() called twice");
+    mContext = ctx;
+  }
+
+  // ========================================================================
+  // Abstract methods
+
+  public abstract void parse(MAnnotatedElement target, Tag tag);
+
+  // ========================================================================
+  // Protected methods
+
+  protected MAnnotation[] createAnnotations(MAnnotatedElement target, Tag tag) {
+    String tagName = tag.name().trim().substring(1);
+    //MAnnotation out = target.addAnnotation(tagName);
+    MAnnotation current = target.getMutableAnnotation(tagName);
+    if (current == null) {
+      current = target.findOrCreateAnnotation(tagName);
+      setPosition(current,tag);
+    }
+    MAnnotation literal = target.addLiteralAnnotation(tagName);
+    setPosition(literal,tag);
+    MAnnotation[] out = new MAnnotation[] {literal,current};
+    if (mAddSingleValueMembers) setSingleValueText(out,tag);
+    return out;
+  }
+
+
+  // subclasses might want to override this to change the way tag values
+  // are mapped into typed values
+  protected void setValue(MAnnotation[] anns,
+                          String memberName,
+                          String value) {
+    value = value.trim();
+    memberName = memberName.trim();
+    for(int i=0; i<anns.length; i++) {
+      if (anns[i].getValue(memberName) == null) {
+        // first one wins
+        anns[i].setSimpleValue(memberName,value,getStringType());
+      }
+    }
+  }
+
+  protected JamLogger getLogger() { return mContext.getLogger(); }
+
+  protected JClass getStringType() {
+    return ((ElementContext)mContext).getClassLoader().
+      loadClass("java.lang.String");
+  }
+
+  //set the value of SINGLE_VALUE_NAME to be the raw tag text.  This of
+  //course will be overridden if the tag contains a member value named
+  //'value' - oh well
+  protected void setSingleValueText(MAnnotation[] targets, Tag tag) {
+    String tagText = tag.text();
+    for(int i=0; i<targets.length; i++) {
+    targets[i].setSimpleValue
+      (JAnnotation.SINGLE_VALUE_NAME,tagText,getStringType());
+    }
+  }
+
+  // ========================================================================
+  // Private methods
+
+  private void setPosition(MAnnotation target, Tag tag) {
+    //add source position info, if available
+    SourcePosition pos = tag.position();
+    if (pos != null) {
+      MSourcePosition mpos = target.createSourcePosition();
+      mpos.setLine(pos.line());
+      mpos.setColumn(pos.column());
+      if (pos.file() != null) mpos.setSourceURI(pos.file().toURI());
+    }
+  }
+
+}

Added: xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/annotation/LineDelimitedTagParser.java
URL: http://svn.apache.org/viewvc/xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/annotation/LineDelimitedTagParser.java?rev=1857518&view=auto
==============================================================================
--- xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/annotation/LineDelimitedTagParser.java (added)
+++ xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/annotation/LineDelimitedTagParser.java Sun Apr 14 13:55:06 2019
@@ -0,0 +1,82 @@
+/*   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.xmlbeans.impl.jam.annotation;
+
+import com.sun.javadoc.Tag;
+import org.apache.xmlbeans.impl.jam.mutable.MAnnotatedElement;
+import org.apache.xmlbeans.impl.jam.mutable.MAnnotation;
+
+import java.io.StringWriter;
+import java.util.StringTokenizer;
+
+/**
+ * <p>Attempts to parse tag contents as a series of line-delimited name-value
+ * pairs.</p>
+ *
+ * @author Patrick Calahan &lt;email: pcal-at-bea-dot-com&gt;
+ */
+public class LineDelimitedTagParser extends JavadocTagParser {
+
+  // ========================================================================
+  // Constants
+
+  private static final String VALUE_QUOTE = "\"";
+  private static final String LINE_DELIMS = "\n\f\r";
+
+  // ========================================================================
+  // JavadocTagParser implementation
+
+  public void parse(MAnnotatedElement target, Tag tag) {
+    if (target == null) throw new IllegalArgumentException("null tagText");
+    if (tag == null) throw new IllegalArgumentException("null tagName");
+    MAnnotation[] anns = createAnnotations(target,tag);
+    String tagText = tag.text();
+    StringTokenizer st = new StringTokenizer(tagText, LINE_DELIMS);
+    while (st.hasMoreTokens()) {
+      String pair = st.nextToken();
+      int eq = pair.indexOf('=');
+      if (eq <= 0) continue; // if absent or is first character
+      String name = pair.substring(0, eq).trim();
+      if (eq < pair.length() - 1) {
+        String value = pair.substring(eq + 1).trim();
+        if (value.startsWith(VALUE_QUOTE)) {
+          value = parseQuotedValue(value.substring(1),st);
+        }
+        setValue(anns,name,value);
+      }
+    }
+  }
+
+  // ========================================================================
+  // Private methods
+
+  private String parseQuotedValue(String line, StringTokenizer st) {
+    StringWriter out = new StringWriter();
+    while(true) {
+      int endQuote = line.indexOf(VALUE_QUOTE);
+      if (endQuote == -1) {
+        out.write(line);
+        if (!st.hasMoreTokens()) return out.toString();
+        out.write('\n');
+        line = st.nextToken().trim();
+        continue;
+      } else {
+        out.write(line.substring(0,endQuote).trim());
+        return out.toString();
+      }
+    }
+  }
+
+}

Added: xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/annotation/TypedAnnotationProxyBase.java
URL: http://svn.apache.org/viewvc/xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/annotation/TypedAnnotationProxyBase.java?rev=1857518&view=auto
==============================================================================
--- xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/annotation/TypedAnnotationProxyBase.java (added)
+++ xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/annotation/TypedAnnotationProxyBase.java Sun Apr 14 13:55:06 2019
@@ -0,0 +1,122 @@
+/*   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.xmlbeans.impl.jam.annotation;
+
+import org.apache.xmlbeans.impl.jam.JAnnotationValue;
+import org.apache.xmlbeans.impl.jam.JClass;
+import org.apache.xmlbeans.impl.jam.internal.elements.AnnotationValueImpl;
+import org.apache.xmlbeans.impl.jam.internal.elements.ElementContext;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * <p>Base for user-defined annotation classes which provide strongly-typed
+ * access to java metadata.  This class implements AnnotationProxy by using
+ * reflection get and set properties on the extending class.  See
+ * documentation on <code>setMemberValue()</code> and
+ * <code>getValue()</code> for details.</p>
+ *
+ * @author Patrick Calahan &lt;email: pcal-at-bea-dot-com&gt;
+ */
+/**
+ * @deprecated do not use, being deleted
+ */
+public abstract class TypedAnnotationProxyBase extends AnnotationProxy {
+
+  // ========================================================================
+  // Variables
+
+  private List mValues = null;
+
+  // ========================================================================
+  // Constructors
+
+  protected TypedAnnotationProxyBase() {}
+
+  // ========================================================================
+  // Public methods
+
+  /**
+   * <p>Sets the member value by introspecting this class and looking for an
+   * appropriate setter method.  For example, if the 'name' parameter is
+   * 'foo', a method called setFoo will be searched for.  If more than one
+   * such method exists, normal java type widening will be performed to select
+   * the most appropriate match.  Type conversion will be performed on the
+   * 'value' object as necessary.</p>
+   *
+   * <p>Extending classes are free to override this method if different
+   * behavior is required.</p>
+   */
+  public void setValue(String name, Object value, JClass type) {
+    if (name == null) throw new IllegalArgumentException("null name");
+    if (value == null) throw new IllegalArgumentException("null value");
+    {
+      // hang onto it in case they ask for it later with getValues
+      if (mValues == null) mValues = new ArrayList();
+      mValues.add(new AnnotationValueImpl
+        ((ElementContext)mContext,name,value,type));
+    }
+    Method m = getSetterFor(name,value.getClass());
+    if (m == null) return;
+    try {
+      m.invoke(this,new Object[] {value});
+    } catch (IllegalAccessException e) {
+      getLogger().warning(e);
+    } catch (InvocationTargetException e) {
+      getLogger().warning(e);
+    }
+  }
+
+  /**
+   * <p>Returns an untyped view of the annotation's values.  These simply
+   * reflect the values which have been passed into it from JAM via the
+   * setValue method.  This means they will just be a direct reflection of
+   * whatever was found on 175 annotation or javadoc tag that is being
+   * proxied.</p>
+   *
+   * <p>Extending classes are encouraged to override this method if different
+   * behavior is required.</p>
+   */
+  public JAnnotationValue[] getValues() {
+    if (mValues == null) return new JAnnotationValue[0];
+    JAnnotationValue[] out = new JAnnotationValue[mValues.size()];
+    mValues.toArray(out);
+    return out;
+  }
+
+  // ========================================================================
+  // Protected methods
+
+  /**
+   * <p>Gets the setter that should be used for setting the given member
+   * with the given value.  This is part of the setMemberValue()
+   * implementation, but is broken out as a separate protected method to
+   * provide a convenient override point for extensions to do simple name
+   * mappings without having to completely re-implement setMemberValue().</p>
+   */
+  protected Method getSetterFor(String memberName, Class valueType) {
+    try {
+      return this.getClass().getMethod("set"+memberName,
+                                       new Class[] {valueType});
+    } catch(NoSuchMethodException nsme) {
+      getLogger().warning(nsme);
+      return null;
+    }
+  }
+}
\ No newline at end of file

Added: xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/annotation/WhitespaceDelimitedTagParser.java
URL: http://svn.apache.org/viewvc/xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/annotation/WhitespaceDelimitedTagParser.java?rev=1857518&view=auto
==============================================================================
--- xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/annotation/WhitespaceDelimitedTagParser.java (added)
+++ xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/annotation/WhitespaceDelimitedTagParser.java Sun Apr 14 13:55:06 2019
@@ -0,0 +1,196 @@
+/*   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.xmlbeans.impl.jam.annotation;
+
+import com.sun.javadoc.Tag;
+import org.apache.xmlbeans.impl.jam.mutable.MAnnotatedElement;
+import org.apache.xmlbeans.impl.jam.mutable.MAnnotation;
+
+import java.util.Enumeration;
+import java.util.Properties;
+
+/**
+ * This provides ejbgen-style tag parsing: tag contents
+ * are treated as whitespace-separated name=value pairs, where values
+ * can be double-quoted.
+ * 
+ * @author Patrick Calahan &lt;email: pcal-at-bea-dot-com&gt;
+ */
+public class WhitespaceDelimitedTagParser extends JavadocTagParser {
+
+  public void parse(MAnnotatedElement target,  Tag tag) {
+    MAnnotation[] anns = createAnnotations(target,tag);
+    String tagText = tag.text();
+    if (tagText == null) return;
+    tagText = tagText.trim();
+    if (tagText.length() == 0) return;
+    Properties props = new Properties();
+    parseAssignments(props,tagText); //FIXME no need to create Properties here
+    if (props.size() > 0) {
+      Enumeration names = props.propertyNames();
+      while(names.hasMoreElements()) {
+        String name = (String)names.nextElement();
+        setValue(anns,name,props.getProperty(name));
+      }
+    } else {
+      //add the single member text if and only if there are no name-value
+      //pairs.  this is how ejbgen likes it but i'm not sure it's the right
+      //thing - might be nicer to have the info always available
+       setSingleValueText(anns,tag);
+    }
+  }
+
+  // ========================================================================
+  // Private methods
+
+  //REVIEW the comment parsing logic here should be factored and made pluggable
+
+  /**
+   * Parse a line that contains assignments, taking into account
+   * - newlines (ignore them)
+   * - double quotes (the value is everything in-between)
+   * - // (everything after is ignored)
+   * - multiple assignments on the same line
+   *
+   * @param out This variable will contain a list of properties
+   * representing the line once parsed.
+   * @param line The line to be parsed
+   *
+   * This method contributed by Cedric Beust
+   */
+  private void parseAssignments(Properties out, String line) {
+    getLogger().verbose("PARSING LINE " + line,this);
+    String originalLine = line;
+    line = removeComments(line);
+    while (null != line && -1 != line.indexOf("=")) {
+      int keyStart = -1;
+      int keyEnd = -1;
+      int ind = 0;
+      // Skip stuff before the key
+      char c = line.charAt(ind);
+      while (isBlank(c)) {
+        ind++;
+        c = line.charAt(ind);
+      }
+      keyStart = ind;
+      while (isLegal(line.charAt(ind))) ind++;
+      keyEnd = ind;
+      String key = line.substring(keyStart, keyEnd);
+      ind = line.indexOf("=");
+      if (ind == -1) {
+        return; //FIXME let's be a little conservative, just for now
+        //throw new IllegalStateException("'=' expected: "+line);
+      }
+      ind++;
+      // Skip stuff after the equal sign
+      try {
+        c = line.charAt(ind);
+      }
+      catch(StringIndexOutOfBoundsException ex){
+        ex.printStackTrace();
+      }
+      while (isBlank(c)) {
+        ind++;
+        c = line.charAt(ind);
+      }
+
+      String value;
+      int valueStart = -1;
+      int valueEnd = -1;
+      if (c == '"') {
+        valueStart = ++ind;
+        while ('"' != line.charAt(ind)) {
+          ind++;
+          if (ind >= line.length()) {
+            getLogger().verbose("missing double quotes on line "+line,this);
+          }
+        }
+        valueEnd = ind;
+      }
+      else {
+        valueStart = ind++;
+        while (ind < line.length() && isLegal(line.charAt(ind))) ind++;
+        valueEnd = ind;
+      }
+      value = line.substring(valueStart, valueEnd);
+      if (ind < line.length()) {
+        line = line.substring(ind + 1);
+      }
+      else {
+        line = null;
+      }
+      getLogger().verbose("SETTING KEY:"+key+" VALUE:"+value,this);
+      out.setProperty(key, value);
+    }
+  }
+
+  /**
+   * Remove all the texts between "//" and '\n'
+   *
+   * This method contributed by Cedric Beust
+   */
+  private String removeComments(String value) {
+    String result = "";
+    int size = value.length();
+    String current = value;
+
+    int currentIndex = 0;
+
+    int beginning = current.indexOf("//");
+
+    //
+    // Ignore // if it's between double quotes
+    //
+    int doubleQuotesIndex = current.indexOf("\"");
+    if (-1 != doubleQuotesIndex && doubleQuotesIndex < beginning) {
+      // do nothing
+      result = value;
+    }
+    else {
+      while (currentIndex < size && beginning != -1) {
+        beginning = value.indexOf("//", currentIndex);
+        if (-1 != beginning) {
+          if (beginning > 0 && value.charAt(beginning-1) == ':') {
+            //this is a quick fix for problem of unquoted url values.  for
+            //now, just say it's not a comment if preceded by ':'.  should
+            //review this later
+            currentIndex = beginning+2;
+            continue;
+          }
+          int end = value.indexOf('\n', beginning);
+          if (-1 == end) end = size;
+          // We have identified a portion to remove, copy the one we want to
+          // keep
+          result = result + value.substring(currentIndex, beginning).trim() + "\n";
+          current = value.substring(end);
+          currentIndex = end;
+        }
+      }
+      result += current;
+    }
+
+    return result.trim();
+  }
+
+  private boolean isBlank(char c) {
+    return c == ' ' || c == '\t' || c == '\n';
+  }
+
+  private boolean isLegal(char c) {
+    return (! isBlank(c)) && c != '=';
+//     return Character.isJavaIdentifierStart(c) || c == '-' || Character.isDigit(c) || c == '.';
+  }
+
+}

Added: xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/internal/CachedClassBuilder.java
URL: http://svn.apache.org/viewvc/xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/internal/CachedClassBuilder.java?rev=1857518&view=auto
==============================================================================
--- xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/internal/CachedClassBuilder.java (added)
+++ xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/internal/CachedClassBuilder.java Sun Apr 14 13:55:06 2019
@@ -0,0 +1,87 @@
+/*   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.apache.xmlbeans.impl.jam.internal;
+
+import org.apache.xmlbeans.impl.jam.mutable.MClass;
+import org.apache.xmlbeans.impl.jam.provider.JamClassBuilder;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>A ClassBuilder that doesn't do any lazy building - it is just a cache
+ * of classes that are used when asked to build one.  This is used by
+ * JamXmlReader, which does all of it's reading and building in a single
+ * pass.</p>
+ *
+ * @author Patrick Calahan &lt;email: pcal-at-bea-dot-com&gt;
+ */
+public class CachedClassBuilder extends JamClassBuilder {
+
+  // ========================================================================
+  // Variables
+
+  private Map mQcname2jclass = null;
+  private List mClassNames = new ArrayList();
+
+  // ========================================================================
+  // Constructors
+
+  public CachedClassBuilder() {}
+
+  // ========================================================================
+  // JamClassBuilder implementation
+
+  public MClass build(String packageName, String className) {
+    if (mQcname2jclass == null) return null;
+    if (packageName.trim().length() > 0) {
+      className = packageName+'.'+className;
+    }
+    return (MClass)mQcname2jclass.get(className);
+  }
+
+  // ========================================================================
+  // Public methods
+
+  public MClass createClassToBuild(String packageName,
+                                   String className,
+                                   String[] importSpecs) {
+    String qualifiedName;
+    if (packageName.trim().length() > 0) {
+      qualifiedName = packageName+'.'+className;
+    } else {
+      qualifiedName = className;
+    }
+    MClass out;
+    if (mQcname2jclass != null) {
+      out = (MClass)mQcname2jclass.get(qualifiedName);
+      if (out != null) return out;
+    } else {
+      mQcname2jclass = new HashMap();
+    }
+    out = super.createClassToBuild(packageName,className, importSpecs);
+    mQcname2jclass.put(qualifiedName,out);
+    mClassNames.add(qualifiedName);
+    return out;
+  }
+
+  public String[] getClassNames() {
+    String[] out = new String[mClassNames.size()];
+    mClassNames.toArray(out);
+    return out;
+  }
+}

Added: xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/internal/DirectoryScanner.java
URL: http://svn.apache.org/viewvc/xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/internal/DirectoryScanner.java?rev=1857518&view=auto
==============================================================================
--- xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/internal/DirectoryScanner.java (added)
+++ xmlbeans/branches/xmlbeans-536/src/jam/org/apache/xmlbeans/impl/jam/internal/DirectoryScanner.java Sun Apr 14 13:55:06 2019
@@ -0,0 +1,753 @@
+/*   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed under the Apache License, Version 2.0 (the "License");
+ *   you may not use this file except in compliance with the License.
+ *   You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+
+package org.apache.xmlbeans.impl.jam.internal;
+
+import org.apache.xmlbeans.impl.jam.provider.JamLogger;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+/**
+ *
+ * @author Patrick Calahan &lt;email: pcal-at-bea-dot-com&gt;
+ */
+public class DirectoryScanner {
+
+  // ========================================================================
+  // Variables
+
+  private boolean mCaseSensitive = true;
+  private File mRoot;
+  private JamLogger mLogger;
+  private List mIncludeList = null;
+  private List mExcludeList = null;
+  private String[] mIncludes;
+  private String[] mExcludes;
+  private Vector mFilesIncluded;
+  private Vector mDirsIncluded;
+  private boolean mIsDirty = false;
+  private String[] mIncludedFilesCache = null;
+
+
+  // ========================================================================
+  // Constructors
+
+  public DirectoryScanner(File dirToScan, JamLogger logger) {
+    if (logger == null) throw new IllegalArgumentException("null logger");
+    mLogger = logger;
+    mRoot = dirToScan;
+  }
+
+  // ========================================================================
+  // Public methods
+
+  public void include(String pattern) {
+    if (mIncludeList == null) mIncludeList = new ArrayList();
+    mIncludeList.add(pattern);
+    mIsDirty = true;
+  }
+
+  public void exclude(String pattern) {
+    if (mExcludeList == null) mExcludeList = new ArrayList();
+    mExcludeList.add(pattern);
+    mIsDirty = true;
+  }
+
+  /**
+   * Scans the root directory with the patterns that have been included
+   * and excluded and returns the names of the resulting file set
+   * relative to the root dir.
+   */
+  public String[] getIncludedFiles() throws IOException {
+    if (!mIsDirty && mIncludedFilesCache != null) {
+      return mIncludedFilesCache;
+    }
+    if (mIncludeList != null) {
+      String[] inc = new String[mIncludeList.size()];
+      mIncludeList.toArray(inc);
+      setIncludes(inc);
+    } else {
+      setIncludes(null);
+    }
+    if (mExcludeList != null) {
+      String[] exc = new String[mExcludeList.size()];
+      mExcludeList.toArray(exc);
+      setExcludes(exc);
+    } else {
+      setExcludes(null);
+    }
+    scan();
+    mIncludedFilesCache = new String[mFilesIncluded.size()];
+    mFilesIncluded.copyInto(mIncludedFilesCache);
+    return mIncludedFilesCache;
+  }
+
+  public void setDirty() {
+    mIsDirty = true;
+  }
+
+  public File getRoot() {
+    return mRoot;
+  }
+
+  // ========================================================================
+  // Private methods
+
+  /**
+   * Sets the list of include patterns to use. All '/' and '\' characters
+   * are replaced by <code>File.separatorChar</code>, so the separator used
+   * need not match <code>File.separatorChar</code>.
+   * <p>
+   * When a pattern ends with a '/' or '\', "**" is appended.
+   *
+   * @param includes A list of include patterns.
+   *                 May be <code>null</code>, indicating that all files
+   *                 should be included. If a non-<code>null</code>
+   *                 list is given, all elements2 must be
+   * non-<code>null</code>.
+   */
+  private void setIncludes(String[] includes) {
+    if (includes == null) {
+      this.mIncludes = null;
+    } else {
+      this.mIncludes = new String[includes.length];
+      for (int i = 0; i < includes.length; i++) {
+        String pattern;
+        pattern = includes[i].replace('/', File.separatorChar).
+                replace('\\', File.separatorChar);
+        if (pattern.endsWith(File.separator)) {
+          pattern += "**";
+        }
+        this.mIncludes[i] = pattern;
+      }
+    }
+  }
+
+
+  /**
+   * Sets the list of exclude patterns to use. All '/' and '\' characters
+   * are replaced by <code>File.separatorChar</code>, so the separator used
+   * need not match <code>File.separatorChar</code>.
+   * <p>
+   * When a pattern ends with a '/' or '\', "**" is appended.
+   *
+   * @param excludes A list of exclude patterns.
+   *                 May be <code>null</code>, indicating that no files
+   *                 should be excluded. If a non-<code>null</code> list is
+   *                 given, all elements2 must be non-<code>null</code>.
+   */
+  private void setExcludes(String[] excludes) {
+    if (excludes == null) {
+      this.mExcludes = null;
+    } else {
+      this.mExcludes = new String[excludes.length];
+      for (int i = 0; i < excludes.length; i++) {
+        String pattern;
+        pattern = excludes[i].replace('/', File.separatorChar).
+                replace('\\', File.separatorChar);
+        if (pattern.endsWith(File.separator)) {
+          pattern += "**";
+        }
+        this.mExcludes[i] = pattern;
+      }
+    }
+  }
+
+
+  /**
+   * Scans the base directory for files which match at least one
+   * include pattern and don't match any exclude patterns. If there
+   * are selectors then the files must pass muster there, as well.
+   *
+   * @exception IllegalStateException if the base directory was set
+   *            incorrectly (i.e. if it is <code>null</code>, doesn't exist,
+   *            or isn't a directory).
+   */
+  private void scan() throws IllegalStateException, IOException {
+    if (mIncludes == null) {
+      // No mIncludes supplied, so set it to 'matches all'
+      mIncludes = new String[1];
+      mIncludes[0] = "**";
+    }
+    if (mExcludes == null) {
+      mExcludes = new String[0];
+    }
+    mFilesIncluded = new Vector();
+    mDirsIncluded = new Vector();
+    if (isIncluded("")) {
+      if (!isExcluded("")) {
+        mDirsIncluded.addElement("");
+      }
+    }
+    scandir(mRoot, "", true);
+  }
+
+  /**
+   * Scans the given directory for files and directories. Found files and
+   * directories are placed in their respective collections, based on the
+   * matching of mIncludes, mExcludes, and the selectors.  When a directory
+   * is found, it is scanned recursively.
+   *
+   * @param dir   The directory to scan. Must not be <code>null</code>.
+   * @param vpath The path relative to the base directory (needed to
+   *              prevent problems with an absolute path when using
+   *              dir). Must not be <code>null</code>.
+   * @param fast  Whether or not this call is part of a fast scan.
+   *
+   * @see #mFilesIncluded
+   * @see #mDirsIncluded
+   */
+  private void scandir(File dir, String vpath, boolean fast)
+          throws IOException {
+    if (mLogger.isVerbose(this)) {
+      mLogger.verbose("[DirectoryScanner] scanning dir "+dir+" for '"+vpath+"'");
+    }
+    String[] newfiles = dir.list();
+    if (newfiles == null) {
+      /*
+      * two reasons are mentioned in the API docs for File.list
+      * (1) dir is not a directory. This is impossible as
+      *     we wouldn't get here in this case.
+      * (2) an IO error occurred (why doesn't it throw an exception
+      *     then???)
+      */
+      throw new IOException("IO error scanning directory "
+                            + dir.getAbsolutePath());
+    }
+    /*
+    if (!followSymlinks) {
+    Vector noLinks = new Vector();
+    for (int i = 0; i < newfiles.length; i++) {
+    try {
+    if (fileUtils.isSymbolicLink(dir, newfiles[i])) {
+    String name = vpath + newfiles[i];
+    File   file = new File(dir, newfiles[i]);
+    if (file.isDirectory()) {
+    dirsExcluded.addElement(name);
+    } else {
+    filesExcluded.addElement(name);
+    }
+    } else {
+    noLinks.addElement(newfiles[i]);
+    }
+    } catch (IOException ioe) {
+    String msg = "IOException caught while checking "
+    + "for links, couldn't get cannonical path!";
+    // will be caught and redirected to Ant's logging system
+    System.err.println(msg);
+    noLinks.addElement(newfiles[i]);
+    }
+    }
+    newfiles = new String[noLinks.size()];
+    noLinks.copyInto(newfiles);
+    }*/
+    for (int i = 0; i < newfiles.length; i++) {
+      String name = vpath + newfiles[i];
+      File file = new File(dir, newfiles[i]);
+      if (file.isDirectory()) {
+        if (isIncluded(name) && !isExcluded(name)) {
+          mDirsIncluded.addElement(name);
+          if (mLogger.isVerbose(this)) mLogger.verbose("...including dir "+name);
+          scandir(file, name + File.separator, fast);
+        } else {
+          if (couldHoldIncluded(name)) {
+            scandir(file, name + File.separator, fast);
+          }
+        }
+      } else if (file.isFile()) {
+        if (isIncluded(name)) {
+          if (!isExcluded(name)) {
+            mFilesIncluded.addElement(name);
+            if (mLogger.isVerbose(this)) {
+              mLogger.verbose("...including "+name+" under '"+dir);
+            }
+          } else {
+            if (mLogger.isVerbose(this)) {
+              mLogger.verbose("...EXCLUDING "+name+" under '"+dir);
+            }
+          }
+        }
+      }
+    }
+  }
+
+  /**
+   * Tests whether or not a name matches against at least one include
+   * pattern.
+   *
+   * @param name The name to match. Must not be <code>null</code>.
+   * @return <code>true</code> when the name matches against at least one
+   *         include pattern, or <code>false</code> otherwise.
+   */
+  private boolean isIncluded(String name) {
+    for (int i = 0; i < mIncludes.length; i++) {
+      if (matchPath(mIncludes[i], name, mCaseSensitive)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /**
+   * Tests whether or not a name matches the start of at least one include
+   * pattern.
+   *
+   * @param name The name to match. Must not be <code>null</code>.
+   * @return <code>true</code> when the name matches against the start of at
+   *         least one include pattern, or <code>false</code> otherwise.
+   */
+  private boolean couldHoldIncluded(String name) {
+    for (int i = 0; i < mIncludes.length; i++) {
+      if (matchPatternStart(mIncludes[i], name, mCaseSensitive)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+  /**
+   * Tests whether or not a name matches against at least one exclude
+   * pattern.
+   *
+   * @param name The name to match. Must not be <code>null</code>.
+   * @return <code>true</code> when the name matches against at least one
+   *         exclude pattern, or <code>false</code> otherwise.
+   */
+  private boolean isExcluded(String name) {
+    for (int i = 0; i < mExcludes.length; i++) {
+      if (matchPath(mExcludes[i], name, mCaseSensitive)) {
+        return true;
+      }
+    }
+    return false;
+  }
+
+
+
+  /**
+   * Returns the names of the directories which matched at least one
+   * of the include patterns and none of the exclude patterns.  The
+   * names are relative to the base directory.
+   *
+   * @return the names of the directories which matched at least one of the
+   * include patterns and none of the exclude patterns.
+
+  private String[] getIncludedDirectories() {
+    String[] directories = new String[mDirsIncluded.size()];
+    mDirsIncluded.copyInto(directories);
+    return directories;
+  }
+   */
+
+  // ========================================================================
+  // SelectorUtils stuff
+
+  /**
+   * Tests whether or not a given path matches the start of a given
+   * pattern up to the first "**".
+   * <p>
+   * This is not a general purpose test and should only be used if you
+   * can live with false positives. For example, <code>pattern=**\a</code>
+   * and <code>str=b</code> will yield <code>true</code>.
+   *
+   * @param pattern The pattern to match against. Must not be
+   *                <code>null</code>.
+   * @param str     The path to match, as a String. Must not be
+   *                <code>null</code>.
+   *
+   * @return whether or not a given path matches the start of a given
+   * pattern up to the first "**".
+
+  private static boolean matchPatternStart(String pattern, String str) {
+    return matchPatternStart(pattern, str, true);
+  }
+   */
+
+  /**
+   * Tests whether or not a given path matches the start of a given
+   * pattern up to the first "**".
+   * <p>
+   * This is not a general purpose test and should only be used if you
+   * can live with false positives. For example, <code>pattern=**\a</code>
+   * and <code>str=b</code> will yield <code>true</code>.
+   *
+   * @param pattern The pattern to match against. Must not be
+   *                <code>null</code>.
+   * @param str     The path to match, as a String. Must not be
+   *                <code>null</code>.
+   * @param mCaseSensitive Whether or not matching should be performed
+   *                        case sensitively.
+   *
+   * @return whether or not a given path matches the start of a given
+   * pattern up to the first "**".
+   */
+  private static boolean matchPatternStart(String pattern, String str,
+                                          boolean mCaseSensitive) {
+    // When str starts with a File.separator, pattern has to start with a
+    // File.separator.
+    // When pattern starts with a File.separator, str has to start with a
+    // File.separator.
+    if (str.startsWith(File.separator) !=
+            pattern.startsWith(File.separator)) {
+      return false;
+    }
+    Vector patDirs = tokenizePath(pattern);
+    Vector strDirs = tokenizePath(str);
+    int patIdxStart = 0;
+    int patIdxEnd = patDirs.size() - 1;
+    int strIdxStart = 0;
+    int strIdxEnd = strDirs.size() - 1;
+    // up to first '**'
+    while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
+      String patDir = (String) patDirs.elementAt(patIdxStart);
+      if (patDir.equals("**")) {
+        break;
+      }
+      if (!match(patDir, (String) strDirs.elementAt(strIdxStart),
+                 mCaseSensitive)) {
+        return false;
+      }
+      patIdxStart++;
+      strIdxStart++;
+    }
+    if (strIdxStart > strIdxEnd) {
+      // String is exhausted
+      return true;
+    } else if (patIdxStart > patIdxEnd) {
+      // String not exhausted, but pattern is. Failure.
+      return false;
+    } else {
+      // pattern now holds ** while string is not exhausted
+      // this will generate false positives but we can live with that.
+      return true;
+    }
+  }
+
+  /**
+   * Tests whether or not a given path matches a given pattern.
+   *
+   * @param pattern The pattern to match against. Must not be
+   *                <code>null</code>.
+   * @param str     The path to match, as a String. Must not be
+   *                <code>null</code>.
+   *
+   * @return <code>true</code> if the pattern matches against the string,
+   *         or <code>false</code> otherwise.
+
+  private static boolean matchPath(String pattern, String str) {
+    return matchPath(pattern, str, true);
+  }
+   */
+  
+  /**
+   * Tests whether or not a given path matches a given pattern.
+   *
+   * @param pattern The pattern to match against. Must not be
+   *                <code>null</code>.
+   * @param str     The path to match, as a String. Must not be
+   *                <code>null</code>.
+   * @param mCaseSensitive Whether or not matching should be performed
+   *                        case sensitively.
+   *
+   * @return <code>true</code> if the pattern matches against the string,
+   *         or <code>false</code> otherwise.
+   */
+  private static boolean matchPath(String pattern, String str,
+                                   boolean mCaseSensitive) {
+    // When str starts with a File.separator, pattern has to start with a
+    // File.separator.
+    // When pattern starts with a File.separator, str has to start with a
+    // File.separator.
+    if (str.startsWith(File.separator) !=
+            pattern.startsWith(File.separator)) {
+      return false;
+    }
+    Vector patDirs = tokenizePath(pattern);
+    Vector strDirs = tokenizePath(str);
+    int patIdxStart = 0;
+    int patIdxEnd = patDirs.size() - 1;
+    int strIdxStart = 0;
+    int strIdxEnd = strDirs.size() - 1;
+    // up to first '**'
+    while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
+      String patDir = (String) patDirs.elementAt(patIdxStart);
+      if (patDir.equals("**")) {
+        break;
+      }
+      if (!match(patDir, (String) strDirs.elementAt(strIdxStart),
+                 mCaseSensitive)) {
+        return false;
+      }
+      patIdxStart++;
+      strIdxStart++;
+    }
+    if (strIdxStart > strIdxEnd) {
+      // String is exhausted
+      for (int i = patIdxStart; i <= patIdxEnd; i++) {
+        if (!patDirs.elementAt(i).equals("**")) {
+          return false;
+        }
+      }
+      return true;
+    } else {
+      if (patIdxStart > patIdxEnd) {
+        // String not exhausted, but pattern is. Failure.
+        return false;
+      }
+    }
+    // up to last '**'
+    while (patIdxStart <= patIdxEnd && strIdxStart <= strIdxEnd) {
+      String patDir = (String) patDirs.elementAt(patIdxEnd);
+      if (patDir.equals("**")) {
+        break;
+      }
+      if (!match(patDir, (String) strDirs.elementAt(strIdxEnd),
+              mCaseSensitive)) {
+        return false;
+      }
+      patIdxEnd--;
+      strIdxEnd--;
+    }
+    if (strIdxStart > strIdxEnd) {
+      // String is exhausted
+      for (int i = patIdxStart; i <= patIdxEnd; i++) {
+        if (!patDirs.elementAt(i).equals("**")) {
+          return false;
+        }
+      }
+      return true;
+    }
+    while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
+      int patIdxTmp = -1;
+      for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
+        if (patDirs.elementAt(i).equals("**")) {
+          patIdxTmp = i;
+          break;
+        }
+      }
+      if (patIdxTmp == patIdxStart + 1) {
+        // '**/**' situation, so skip one
+        patIdxStart++;
+        continue;
+      }
+      // Find the pattern between padIdxStart & padIdxTmp in str between
+      // strIdxStart & strIdxEnd
+      int patLength = (patIdxTmp - patIdxStart - 1);
+      int strLength = (strIdxEnd - strIdxStart + 1);
+      int foundIdx = -1;
+      strLoop:
+        for (int i = 0; i <= strLength - patLength; i++) {
+          for (int j = 0; j < patLength; j++) {
+            String subPat = (String) patDirs.elementAt(patIdxStart + j + 1);
+            String subStr = (String) strDirs.elementAt(strIdxStart + i + j);
+            if (!match(subPat, subStr, mCaseSensitive)) {
+              continue strLoop;
+            }
+          }
+          foundIdx = strIdxStart + i;
+          break;
+        }
+      if (foundIdx == -1) {
+        return false;
+      }
+      patIdxStart = patIdxTmp;
+      strIdxStart = foundIdx + patLength;
+    }
+    for (int i = patIdxStart; i <= patIdxEnd; i++) {
+      if (!patDirs.elementAt(i).equals("**")) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+
+  /**
+   * Tests whether or not a string matches against a pattern.  The
+   * pattern may contain two special characters:<br> '*' means zero or
+   * more characters<br> '?' means one and only one character
+   *
+   * @param pattern The pattern to match against.
+   *                Must not be <code>null</code>.
+   * @param str     The string which must be matched against the pattern.
+   *                Must not be <code>null</code>.
+   * @param mCaseSensitive Whether or not matching should be performed
+   *                        case sensitively.
+   *
+   *
+   * @return <code>true</code> if the string matches against the pattern,
+   *         or <code>false</code> otherwise.
+   */
+  private static boolean match(String pattern, String str,
+                               boolean mCaseSensitive) {
+    char[] patArr = pattern.toCharArray();
+    char[] strArr = str.toCharArray();
+    int patIdxStart = 0;
+    int patIdxEnd = patArr.length - 1;
+    int strIdxStart = 0;
+    int strIdxEnd = strArr.length - 1;
+    char ch;
+    boolean containsStar = false;
+    for (int i = 0; i < patArr.length; i++) {
+      if (patArr[i] == '*') {
+        containsStar = true;
+        break;
+      }
+    }
+    if (!containsStar) {
+      // No '*'s, so we make a shortcut
+      if (patIdxEnd != strIdxEnd) {
+        return false; // Pattern and string do not have the same size
+      }
+      for (int i = 0; i <= patIdxEnd; i++) {
+        ch = patArr[i];
+        if (ch != '?') {
+          if (mCaseSensitive && ch != strArr[i]) {
+            return false;// Character mismatch
+          }
+          if (!mCaseSensitive && Character.toUpperCase(ch) !=
+                  Character.toUpperCase(strArr[i])) {
+            return false; // Character mismatch
+          }
+        }
+      }
+      return true; // String matches against pattern
+    }
+    if (patIdxEnd == 0) {
+      return true; // Pattern contains only '*', which matches anything
+    }
+    // Process characters before first star
+    while ((ch = patArr[patIdxStart]) != '*' && strIdxStart <= strIdxEnd) {
+      if (ch != '?') {
+        if (mCaseSensitive && ch != strArr[strIdxStart]) {
+          return false;// Character mismatch
+        }
+        if (!mCaseSensitive && Character.toUpperCase(ch) !=
+                Character.toUpperCase(strArr[strIdxStart])) {
+          return false;// Character mismatch
+        }
+      }
+      patIdxStart++;
+      strIdxStart++;
+    }
+    if (strIdxStart > strIdxEnd) {
+      // All characters in the string are used. Check if only '*'s are
+      // left in the pattern. If so, we succeeded. Otherwise failure.
+      for (int i = patIdxStart; i <= patIdxEnd; i++) {
+        if (patArr[i] != '*') {
+          return false;
+        }
+      }
+      return true;
+    }
+    // Process characters after last star
+    while ((ch = patArr[patIdxEnd]) != '*' && strIdxStart <= strIdxEnd) {
+      if (ch != '?') {
+        if (mCaseSensitive && ch != strArr[strIdxEnd]) {
+          return false;// Character mismatch
+        }
+        if (!mCaseSensitive && Character.toUpperCase(ch) !=
+                Character.toUpperCase(strArr[strIdxEnd])) {
+          return false;// Character mismatch
+        }
+      }
+      patIdxEnd--;
+      strIdxEnd--;
+    }
+    if (strIdxStart > strIdxEnd) {
+      // All characters in the string are used. Check if only '*'s are
+      // left in the pattern. If so, we succeeded. Otherwise failure.
+      for (int i = patIdxStart; i <= patIdxEnd; i++) {
+        if (patArr[i] != '*') {
+          return false;
+        }
+      }
+      return true;
+    }
+    // process pattern between stars. padIdxStart and patIdxEnd point
+    // always to a '*'.
+    while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) {
+      int patIdxTmp = -1;
+      for (int i = patIdxStart + 1; i <= patIdxEnd; i++) {
+        if (patArr[i] == '*') {
+          patIdxTmp = i;
+          break;
+        }
+      }
+      if (patIdxTmp == patIdxStart + 1) {
+        // Two stars next to each other, skip the first one.
+        patIdxStart++;
+        continue;
+      }
+      // Find the pattern between padIdxStart & padIdxTmp in str between
+      // strIdxStart & strIdxEnd
+      int patLength = (patIdxTmp - patIdxStart - 1);
+      int strLength = (strIdxEnd - strIdxStart + 1);
+      int foundIdx = -1;
+      strLoop:
+        for (int i = 0; i <= strLength - patLength; i++) {
+          for (int j = 0; j < patLength; j++) {
+            ch = patArr[patIdxStart + j + 1];
+            if (ch != '?') {
+              if (mCaseSensitive && ch != strArr[strIdxStart + i + j]) {
+                continue strLoop;
+              }
+              if (!mCaseSensitive && Character.toUpperCase(ch) !=
+                      Character.toUpperCase(strArr[strIdxStart + i + j])) {
+                continue strLoop;
+              }
+            }
+          }
+          foundIdx = strIdxStart + i;
+          break;
+        }
+      if (foundIdx == -1) {
+        return false;
+      }
+      patIdxStart = patIdxTmp;
+      strIdxStart = foundIdx + patLength;
+    }
+    // All characters in the string are used. Check if only '*'s are left
+    // in the pattern. If so, we succeeded. Otherwise failure.
+    for (int i = patIdxStart; i <= patIdxEnd; i++) {
+      if (patArr[i] != '*') {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  /**
+   * Breaks a path up into a Vector of path elements2, tokenizing on
+   * <code>File.separator</code>.
+   *
+   * @param path Path to tokenize. Must not be <code>null</code>.
+   *
+   * @return a Vector of path elements2 from the tokenized path
+   */
+  private static Vector tokenizePath(String path) {
+    Vector ret = new Vector();
+    StringTokenizer st = new StringTokenizer(path, File.separator);
+    while (st.hasMoreTokens()) {
+      ret.addElement(st.nextToken());
+    }
+    return ret;
+  }
+}
\ No newline at end of file



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@poi.apache.org
For additional commands, e-mail: commits-help@poi.apache.org


Mime
View raw message