You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@uima.apache.org by sc...@apache.org on 2013/06/18 22:25:40 UTC

svn commit: r1494286 - in /uima/uimaj/trunk/uimaj-core/src: main/java/org/apache/uima/ main/java/org/apache/uima/cas/impl/ main/java/org/apache/uima/util/ main/resources/org/apache/uima/ test/java/org/apache/uima/cas_data/impl/ test/java/org/apache/uim...

Author: schor
Date: Tue Jun 18 20:25:39 2013
New Revision: 1494286

URL: http://svn.apache.org/r1494286
Log:
[UIMA-2409] Add copyCasView with target new view.  Add one little test case, add a new comparator to check the results.

Added:
    uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/cas_data/impl/CasComparerViewChange.java   (with props)
Modified:
    uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/UIMARuntimeException.java
    uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/CASImpl.java
    uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/util/CasCopier.java
    uima/uimaj/trunk/uimaj-core/src/main/resources/org/apache/uima/UIMAException_Messages.properties
    uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/util/CasCopierTest.java

Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/UIMARuntimeException.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/UIMARuntimeException.java?rev=1494286&r1=1494285&r2=1494286&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/UIMARuntimeException.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/UIMARuntimeException.java Tue Jun 18 20:25:39 2013
@@ -102,6 +102,11 @@ public class UIMARuntimeException extend
 
   /**
    * Message key for a standard UIMA exception message: 
+   * "CAS Copying of the same view to the same CAS with the same view name is not allowed."
+   */
+  public static final String ILLEGAL_CAS_COPY_TO_SAME_CAS_SAME_VIEW = "illegal_copy_same_cas_same_view";
+  /**
+   * Message key for a standard UIMA exception message: 
    * Saved UIMA context is null; probable cause: Annotator initialize(context) method failed to call super.initialize(context). 
    */
   public static final String UIMA_CONTEXT_NULL = "uima_context_null";

Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/CASImpl.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/CASImpl.java?rev=1494286&r1=1494285&r2=1494286&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/CASImpl.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/cas/impl/CASImpl.java Tue Jun 18 20:25:39 2013
@@ -2570,6 +2570,7 @@ public class CASImpl extends AbstractCas
     // get Sofa and switch to view
     SofaFS sofa = getSofa(absoluteSofaName);
     // sofa guaranteed to be non-null by above method
+    // unless sofa doesn't exist, which will cause a throw.
     return getView(sofa);
   }
 

Modified: uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/util/CasCopier.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/util/CasCopier.java?rev=1494286&r1=1494285&r2=1494286&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/util/CasCopier.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/java/org/apache/uima/util/CasCopier.java Tue Jun 18 20:25:39 2013
@@ -26,6 +26,7 @@ import java.util.Map;
 import java.util.Set;
 
 import org.apache.uima.UIMARuntimeException;
+import org.apache.uima.cas.AnnotationBaseFS;
 import org.apache.uima.cas.ArrayFS;
 import org.apache.uima.cas.BooleanArrayFS;
 import org.apache.uima.cas.ByteArrayFS;
@@ -56,11 +57,18 @@ import org.apache.uima.cas.text.Annotati
 public class CasCopier {
   private CAS mSrcCas;
   private CAS mDestCas;
+  private String mSrcCasViewName;
+  private String mTgtCasViewName;
   private LowLevelCAS mLowLevelDestCas;
-  private Feature mDestSofaFeature;
-  private boolean lenient = false; //true: ignore feature structures and features that are not defined in the destination CAS
+  final private Feature mDestSofaFeature;
+  final private boolean lenient; //true: ignore feature structures and features that are not defined in the destination CAS
 
-  private Map<FeatureStructure, FeatureStructure> mFsMap = new HashMap<FeatureStructure, FeatureStructure>();
+  /**
+   * key is source FS, value is target FS 
+   * Target not set for DocumentAnnotation or SofaFSs
+   * Target not set if lenient specified and src type isn't in target
+   */
+  final private Map<FeatureStructure, FeatureStructure> mFsMap = new HashMap<FeatureStructure, FeatureStructure>();
   
   /**
    * feature structures whose slots need copying are put on this list, together with their source
@@ -103,7 +111,6 @@ public class CasCopier {
   public CasCopier(CAS aSrcCas, CAS aDestCas, boolean lenient) {
     mSrcCas = aSrcCas;
     mDestCas = aDestCas;
-    mLowLevelDestCas = aDestCas.getLowLevelCAS();
     mDestSofaFeature = aDestCas.getTypeSystem().getFeatureByFullName(CAS.FEATURE_FULL_NAME_SOFA);    
     this.lenient = lenient;
   }
@@ -167,38 +174,136 @@ public class CasCopier {
   }
 
   /**
-   * Does a deep copy of the contents of one CAS View into another CAS.
-   * If a view with the same name as <code>aSrcCasView</code> exists in the destination CAS,
+   * Does a deep copy of the contents of one CAS View into another CAS's same-named-view
+   * If the destination view already exists in the destination CAS,
    * then it will be the target of the copy.  Otherwise, a new view will be created with
-   * that name and will become the target of the copy.  All FeatureStructures that are indexed 
+   * that name and will become the target of the copy.  All FeatureStructures 
+   * (except for those dropped because the target type system doesn't have the needed type) that are indexed 
+   * in the source CAS view will become indexed in the target view.
+   * Cross-view references may result in creating additional views in the destination CAS;
+   * for these views, any Sofa data in the source is *not* copied.
+   * 
+   * @param aSrcCasView the CAS to copy from
+   * @param aCopySofa if true, the sofa data and mimeType will be copied. If false they will not.
+   */
+  public void copyCasView(CAS aSrcCasView, boolean aCopySofa) {
+    copyCasView(aSrcCasView, getOrCreateView(mDestCas, aSrcCasView.getViewName()), aCopySofa);
+  }
+  
+  /**
+   * Does a deep copy of the contents of one CAS View into another CAS's same-named-view
+   * If the destination view already exists in the destination CAS,
+   * then it will be the target of the copy.  Otherwise, a new view will be created with
+   * that name and will become the target of the copy.  All FeatureStructures 
+   * (except for those dropped because the target type system doesn't have the needed type) that are indexed 
+   * in the source CAS view will become indexed in the target view.
+   * Cross-view references may result in creating additional views in the destination CAS;
+   * for these views, any Sofa data in the source is *not* copied.  Any views created because
+   * of cross-view references will have the same view name as in the source.
+   * 
+   * @param aSrcCasViewName the name of the view in the source CAS to copy from
+   * @param aCopySofa if true, the sofa data and mimeType will be copied. If false they will not.
+   */
+  public void copyCasView(String aSrcCasViewName, boolean aCopySofa) {
+    copyCasView(getOrCreateView(mSrcCas, aSrcCasViewName), aCopySofa);
+  }
+  
+  /**
+   * Does a deep copy of the contents of one CAS View into another CAS view,
+   * with a possibly different name.
+   * If the destination view already exists in the destination CAS,
+   * then it will be the target of the copy.  Otherwise, a new view will be created with
+   * that name and will become the target of the copy.  All FeatureStructures 
+   * (except for those dropped because the target type system doesn't have the needed type) that are indexed 
+   * in the source CAS view will become indexed in the target view.
+   * Cross-view references may result in creating additional views in the destination CAS;
+   * for these views, any Sofa data in the source is *not* copied.  Any views created because
+   * of cross-view references will have the same view name as in the source.
+   * 
+   * @param aSrcCasView The view in the source to copy from
+   * @param aTgtCasViewName The name of the view in the destination CAS to copy into
+   * @param aCopySofa if true, the sofa data and mimeType will be copied. If false they will not.
+   */
+  public void copyCasView(CAS aSrcCasView, String aTgtCasViewName, boolean aCopySofa) {
+    copyCasView(aSrcCasView, getOrCreateView(mDestCas, aTgtCasViewName), aCopySofa);
+  }
+
+  /**
+   * Does a deep copy of the contents of one CAS View into another CAS view,
+   * with a possibly different name.
+   * All FeatureStructures 
+   * (except for those dropped because the target type system doesn't have the needed type) that are indexed 
+   * in the source CAS view will become indexed in the target view.
+   * Cross-view references may result in creating additional views in the destination CAS;
+   * for these views, any Sofa data in the source is *not* copied.  Any views created because
+   * of cross-view references will have the same view name as in the source.
+   * 
+   * @param aSrcCasViewName The name of the view in the Source CAS to copy from
+   * @param aTgtCasView The view in the destination CAS to copy into
+   * @param aCopySofa if true, the sofa data and mimeType will be copied. If false they will not.
+   */
+  public void copyCasView(String aSrcCasViewName, CAS aTgtCasView, boolean aCopySofa) {
+    copyCasView(getOrCreateView(mSrcCas, aSrcCasViewName), aTgtCasView, aCopySofa);
+  }
+
+  /**
+   * Does a deep copy of the contents of one CAS View into another CAS view,
+   * with a possibly different name.
+   * All FeatureStructures 
+   * (except for those dropped because the target type system doesn't have the needed type) that are indexed 
    * in the source CAS view will become indexed in the target view.
+   * Cross-view references may result in creating additional views in the destination CAS;
+   * for these views, any Sofa data in the source is *not* copied.  Any views created because
+   * of cross-view references will have the same view name as in the source.
    * 
    * @param aSrcCasView
    *          the CAS to copy from
    * @param aCopySofa
    *          if true, the sofa data and mimeType will be copied. If false they will not.
    */
-  public void copyCasView(CAS aSrcCasView, boolean aCopySofa) {
-    // get or create the target view
-    CAS targetView = getOrCreateView(mDestCas, aSrcCasView.getViewName());
-
+  public void copyCasView(CAS aSrcCasView, CAS aTgtCasView, boolean aCopySofa) {
+    if (aSrcCasView == aTgtCasView) {
+      throw new UIMARuntimeException(UIMARuntimeException.ILLEGAL_CAS_COPY_TO_SAME_CAS_SAME_VIEW, null);
+    }
+    
+    mSrcCas = aSrcCasView;
+    mSrcCasViewName = aSrcCasView.getViewName();
+       
+    mDestCas = aTgtCasView;
+    mTgtCasViewName = aTgtCasView.getViewName();
+    
+    mLowLevelDestCas = mDestCas.getLowLevelCAS();
+    
+    // The top level sofa associated with this view is copied (or not)
+    
     if (aCopySofa) {
       // can't copy the SofaFS - just copy the sofa data and mime type
       SofaFS sofa = aSrcCasView.getSofa();
       if (null != sofa) {
+        // if the sofa doesn't exist in the target, these calls will create it
+        //  (view can exist without Sofa, at least for the initial view)
         String sofaMime = sofa.getSofaMime();
         if (aSrcCasView.getDocumentText() != null) {
-          targetView.setSofaDataString(aSrcCasView.getDocumentText(), sofaMime);
+          aTgtCasView.setSofaDataString(aSrcCasView.getDocumentText(), sofaMime);
         } else if (aSrcCasView.getSofaDataURI() != null) {
-          targetView.setSofaDataURI(aSrcCasView.getSofaDataURI(), sofaMime);
+          aTgtCasView.setSofaDataURI(aSrcCasView.getSofaDataURI(), sofaMime);
         } else if (aSrcCasView.getSofaDataArray() != null) {
-          targetView.setSofaDataArray(copyFs(aSrcCasView.getSofaDataArray()), sofaMime);
+          aTgtCasView.setSofaDataArray(copyFs2(aSrcCasView.getSofaDataArray()), sofaMime);
         }
       }
     }
 
     // now copy indexed FS, but keep track so we don't index anything more than once
+    //   Note: mFsMap might be used for this, but it doesn't index several kinds of FSs
+    //         see the javadoc for this field for details
+    // NOTE: FeatureStructure hashcode / equals use the int "address" of the FS in the heap.
+    
     Set<FeatureStructure> indexedFs = new HashSet<FeatureStructure>();
+    
+    // We don't clear the map here, in order to skip actually copying the
+    //   FSs when doing a full CAS copy with multiple views - the 2nd and subsequent
+    //   views don't copy, but they do index.
+    
     Iterator<FSIndex<FeatureStructure>> indexes = aSrcCasView.getIndexRepository().getIndexes();
     while (indexes.hasNext()) {
       FSIndex<FeatureStructure> index = indexes.next();
@@ -206,7 +311,7 @@ public class CasCopier {
       while (iter.hasNext()) {
         FeatureStructure fs = iter.next();
         if (!indexedFs.contains(fs)) {
-          FeatureStructure copyOfFs = copyFs(fs);
+          FeatureStructure copyOfFs = copyFs2(fs);
           // If the lenient option is used, it's possible that no FS was
           // created (e.g., FS is not defined in the target CAS. So ignore
           // this FS in the source CAS and move on to the next FS.
@@ -219,15 +324,15 @@ public class CasCopier {
           // if the annotations were created with the Low Level CAS API. If the
           // Sofa reference isn't set, attempting to add the FS to the indexes
           // will fail.
-          if (fs instanceof AnnotationFS) {
-            FeatureStructure sofa = ((AnnotationFS) copyOfFs).getFeatureValue(mDestSofaFeature);
+          if (fs instanceof AnnotationBaseFS) {
+            FeatureStructure sofa = ((AnnotationBaseFS) copyOfFs).getFeatureValue(mDestSofaFeature);
             if (sofa == null) {
-              copyOfFs.setFeatureValue(mDestSofaFeature, targetView.getSofa());
+              copyOfFs.setFeatureValue(mDestSofaFeature, aTgtCasView.getSofa());
             }
           }
           // also don't index the DocumentAnnotation (it's indexed by default)
           if (!isDocumentAnnotation(copyOfFs)) {
-            targetView.addFsToIndexes(copyOfFs);
+            aTgtCasView.addFsToIndexes(copyOfFs);
           }
           indexedFs.add(fs);
         }
@@ -250,7 +355,35 @@ public class CasCopier {
    * 
    */
   
+  /**
+   * Copy 1 feature structure to a new Cas View.  No indexing of the new FS is done.
+   * If the FS has been copied previously (using this CasCopier instance) the 
+   * same identical copy will be returned rather than making another copy.
+   * 
+   * @param aFS
+   * @return
+   */
+  
   public FeatureStructure copyFs(FeatureStructure aFS) {
+    // note these variables are null if copyFs is called after
+    //   creating an instance of this class
+    if (null == mSrcCasViewName) {
+      mSrcCasViewName = mSrcCas.getViewName();
+    }
+    
+    if (null == mTgtCasViewName) {
+      mTgtCasViewName = mDestCas.getViewName();
+    }
+    
+    if (null == mLowLevelDestCas) {
+      mLowLevelDestCas = mDestCas.getLowLevelCAS();
+    }
+    
+    return copyFs2(aFS);
+  }
+  
+  private FeatureStructure copyFs2(FeatureStructure aFS) {
+    
     FeatureStructure copy = copyFsInner(aFS);  // doesn't copy the slot values, but enqueues them
     while (!fsToDo.isEmpty()) {
       FeatureStructure copyToFillSlots = fsToDo.remove(fsToDo.size()-1);
@@ -268,7 +401,7 @@ public class CasCopier {
    *          the FS to copy. Must be contained within the source CAS.
    * @return the copy of <code>aFS</code> in the target CAS.
    */
-  public FeatureStructure copyFsInner(FeatureStructure aFS) {
+  private FeatureStructure copyFsInner(FeatureStructure aFS) {
     // FS must be in the source CAS
     assert ((CASImpl) aFS.getCAS()).getBaseCAS() == ((CASImpl) mSrcCas).getBaseCAS();
 
@@ -285,17 +418,23 @@ public class CasCopier {
     // Sofa - cannot be created by normal methods. Instead, we return the Sofa with the
     // same Sofa ID in the target CAS. If it does not exist it will be created.
     if (aFS instanceof SofaFS) {
-      String sofaId = ((SofaFS) aFS).getSofaID();
-      return getOrCreateView(mDestCas, sofaId).getSofa();
+      String destSofaId = getDestSofaId(((SofaFS) aFS).getSofaID());
+      return getOrCreateView(mDestCas, destSofaId).getSofa();
     }
 
     // DocumentAnnotation - instead of creating a new instance, reuse the automatically created
     // instance in the destination view.
     if (isDocumentAnnotation(aFS)) {
-      String viewName = ((AnnotationFS) aFS).getView().getViewName();
-      CAS destView = mDestCas.getView(viewName);
+      String destViewName = getDestSofaId(((AnnotationFS) aFS).getView().getViewName());
+
+      // the DocumentAnnotation could be indexed in a different view than the one being copied
+      // Note: The view might not exist in the target
+      //   but this is unlikely.  To have this case this would require
+      //   indexing some other feature structure in this view, which, in turn,
+      //   has a reference to the DocumentAnnotation FS belonging to another view
+      CAS destView = getOrCreateView(mDestCas, destViewName);
       FeatureStructure destDocAnnot = destView.getDocumentAnnotation();
-      if (destDocAnnot != null) {
+      if (destDocAnnot != null) {  // Note: is always non-null, getDocumentAnnotation creates if not exist
         copyFeatures(aFS, destDocAnnot);
       }
       return destDocAnnot;
@@ -325,9 +464,10 @@ public class CasCopier {
     // CAS.createFS() call doesn't allow us to create subtypes of AnnotationBase from
     // a base CAS. In any case we don't need the Sofa reference to be automatically
     // set because we'll set it manually when in the copyFeatures method.
+    
     int typeCode = mLowLevelDestCas.ll_getTypeSystem().ll_getCodeForType(destType);
     int destFsAddr = mLowLevelDestCas.ll_createFS(typeCode);
-    FeatureStructure destFs = mDestCas.getLowLevelCAS().ll_getFSForRef(destFsAddr);
+    FeatureStructure destFs = mLowLevelDestCas.ll_getFSForRef(destFsAddr);
 
     // add to map so we don't try to copy this more than once
     mFsMap.put(aFS, destFs);
@@ -337,6 +477,10 @@ public class CasCopier {
     return destFs;
   }
   
+  private String getDestSofaId(String id) {
+    return mSrcCasViewName.equals(id) ? mTgtCasViewName : id;
+  }
+  
   /**
    * Copy feature values from one FS to another. For reference-valued features, this does a deep
    * copy.
@@ -393,6 +537,9 @@ public class CasCopier {
   }
 
   /**
+   * Note: if lenient is in effect, this method will return false for
+   * FSs which are not copied because the target doesn't have that type.
+   * It also returns false for sofa FSs and the documentAnnotation FS.
    * @param aFS a feature structure
    * @return true if the given FS has already been copied using this CasCopier.
    */

Modified: uima/uimaj/trunk/uimaj-core/src/main/resources/org/apache/uima/UIMAException_Messages.properties
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/main/resources/org/apache/uima/UIMAException_Messages.properties?rev=1494286&r1=1494285&r2=1494286&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/main/resources/org/apache/uima/UIMAException_Messages.properties (original)
+++ uima/uimaj/trunk/uimaj-core/src/main/resources/org/apache/uima/UIMAException_Messages.properties Tue Jun 18 20:25:39 2013
@@ -39,6 +39,8 @@ define_cas_pool_called_twice = The metho
        
 unsupported_cas_interface = Unsupported CAS interface {0}.
 
+illegal_copy_same_cas_same_view = CAS Copying of the same view to the same CAS with the same view name is not allowed.
+
 type_not_found_during_cas_copy = Attempted to copy a FeatureStructure of type "{0}", which is not defined in the type system of the destination CAS.
 
 feature_not_found_during_cas_copy = Attempted to copy a Feature "{0}", which is not defined in the type system of the destination CAS.

Added: uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/cas_data/impl/CasComparerViewChange.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/cas_data/impl/CasComparerViewChange.java?rev=1494286&view=auto
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/cas_data/impl/CasComparerViewChange.java (added)
+++ uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/cas_data/impl/CasComparerViewChange.java Tue Jun 18 20:25:39 2013
@@ -0,0 +1,183 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.uima.cas_data.impl;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import junit.framework.Assert;
+import static junit.framework.Assert.*;
+
+import org.apache.uima.cas.ArrayFS;
+import org.apache.uima.cas.CAS;
+import org.apache.uima.cas.FSIterator;
+import org.apache.uima.cas.Feature;
+import org.apache.uima.cas.FeatureStructure;
+import org.apache.uima.cas.FloatArrayFS;
+import org.apache.uima.cas.IntArrayFS;
+import org.apache.uima.cas.SofaFS;
+import org.apache.uima.cas.StringArrayFS;
+import org.apache.uima.cas.Type;
+import org.apache.uima.cas.impl.CASImpl;
+import org.apache.uima.cas.text.AnnotationFS;
+
+/**
+ * A non-perfect CAS equality checker for JUnit with different views
+ * for testing copyCasView
+ * 
+ */
+public class CasComparerViewChange {
+  
+  private final CAS view1;
+  private final CAS view2;
+  private final String view1Name;
+  private final String view2Name;
+  
+  private final Set<FeatureStructure> visited = new HashSet<FeatureStructure>();
+  
+  public CasComparerViewChange(CAS view1, CAS view2) {
+    this.view1 = view1;
+    this.view2 = view2;
+    view1Name = view1.getViewName();
+    view2Name = view2.getViewName();
+  }
+  
+  public void assertEqualViews() {
+    visited.clear();
+    FSIterator<FeatureStructure> it1 = view1.getIndexRepository().getAllIndexedFS(view1.getTypeSystem().getTopType());
+    FSIterator<FeatureStructure> it2 = view2.getIndexRepository().getAllIndexedFS(view2.getTypeSystem().getTopType());
+    while (it1.isValid()) {
+      assertTrue(it2.isValid());
+
+      FeatureStructure fs1 = it1.get();
+      FeatureStructure fs2 = it2.get();
+      assertFsEqual(fs1, fs2);
+      
+      it1.moveToNext();
+      it2.moveToNext();
+    }
+  }
+  
+ private void assertFsEqual(FeatureStructure fs1, FeatureStructure fs2) {
+    if (fs1 == null) {
+      assertNull(fs2);
+    } else {
+      assertNotNull(fs2);
+    }
+
+    if (visited.contains(fs1) || null == fs1) {
+      return;
+    }
+    visited.add(fs1);
+
+    // System.out.println("Comparing " + fs1.getType().getName());
+    assertEquals(fs1.getType().getName(), fs2.getType().getName());
+
+    if (fs1 instanceof SofaFS &&
+        ((SofaFS)fs1).getSofaID().equals(view1Name) &&
+        ((SofaFS)fs2).getSofaID().equals(view2Name)) {
+      return;
+    }
+    
+    List<Feature> features1 = fs1.getType().getFeatures();
+    List<Feature> features2 = fs2.getType().getFeatures();
+    for (int i = 0; i < features1.size(); i++) {
+      Feature feat1 = features1.get(i);
+      Feature feat2 = features2.get(i);
+      // System.out.println("Comparing " + feat1.getName());
+      Type rangeType1 = feat1.getRange();
+      Type rangeType2 = feat2.getRange();
+      Assert.assertEquals(rangeType1.getName(), rangeType2.getName());
+      // System.out.println("Range type " + rangeType1);
+      String rangeTypeName = rangeType1.getName();
+
+      if (fs1.getCAS().getTypeSystem().subsumes(
+              fs1.getCAS().getTypeSystem().getType(CAS.TYPE_NAME_STRING), rangeType1)) {
+        assertEquals(fs1.getStringValue(feat1), fs2.getStringValue(feat2));
+      } else if (CAS.TYPE_NAME_INTEGER.equals(rangeTypeName)) {
+        assertEquals(fs1.getIntValue(feat1), fs2.getIntValue(feat2));
+      } else if (CAS.TYPE_NAME_FLOAT.equals(rangeTypeName)) {
+        assertEquals(fs1.getFloatValue(feat1), fs2.getFloatValue(feat2), 0);
+      } else if (CAS.TYPE_NAME_STRING_ARRAY.equals(rangeTypeName)) {
+        StringArrayFS arrayFS1 = (StringArrayFS) fs1.getFeatureValue(feat1);
+        StringArrayFS arrayFS2 = (StringArrayFS) fs2.getFeatureValue(feat2);
+        if ((arrayFS1 == null) && (arrayFS2 == null)) {
+          // ok
+        } else {
+          Assert.assertEquals(arrayFS1.size(), arrayFS2.size());
+          for (int j = 0; j < arrayFS1.size(); j++) {
+            // Temporary workaround for UIMA-2490 - null and "" string values
+            String s1 = arrayFS1.get(j);
+            String s2 = arrayFS2.get(j);
+            if ((s1 == null) && (s2 != null) && (s2.length() == 0)) {
+              continue;
+            }
+            if ((s2 == null) && (s1 != null) && (s1.length() == 0)) {
+              continue;
+            }
+            assertEquals(arrayFS1.get(j), arrayFS2.get(j));
+          }
+        }
+      } else if (CAS.TYPE_NAME_INTEGER_ARRAY.equals(rangeTypeName)) {
+        IntArrayFS arrayFS1 = (IntArrayFS) fs1.getFeatureValue(feat1);
+        IntArrayFS arrayFS2 = (IntArrayFS) fs2.getFeatureValue(feat2);
+        if ((arrayFS1 == null) && (arrayFS2 == null)) {
+          // ok
+        } else {
+          assertEquals(arrayFS1.size(), arrayFS2.size());
+          for (int j = 0; j < arrayFS1.size(); j++) {
+            assertEquals(arrayFS1.get(j), arrayFS2.get(j));
+          }
+        }
+      } else if (CAS.TYPE_NAME_FLOAT_ARRAY.equals(rangeTypeName)) {
+        FloatArrayFS arrayFS1 = (FloatArrayFS) fs1.getFeatureValue(feat1);
+        FloatArrayFS arrayFS2 = (FloatArrayFS) fs2.getFeatureValue(feat2);
+        if ((arrayFS1 == null) && (arrayFS2 == null)) {
+          // ok
+        } else {
+          assertEquals(arrayFS1.size(), arrayFS2.size());
+          for (int j = 0; j < arrayFS1.size(); j++) {
+            assertEquals(arrayFS1.get(j), arrayFS2.get(j), 0);
+          }
+        }
+      } else if (CAS.TYPE_NAME_FS_ARRAY.equals(rangeTypeName)) {
+        ArrayFS arrayFS1 = (ArrayFS) fs1.getFeatureValue(feat1);
+        ArrayFS arrayFS2 = (ArrayFS) fs2.getFeatureValue(feat2);
+        if ((arrayFS1 == null) && (arrayFS2 == null)) {
+          // ok
+        } else {
+          assertEquals(arrayFS1.size(), arrayFS2.size());
+          for (int j = 0; j < arrayFS1.size(); j++) {
+            assertFsEqual(arrayFS1.get(j), arrayFS2.get(j));
+          }
+        }
+      } else // single feature value
+      {
+        FeatureStructure fsVal1 = fs1.getFeatureValue(feat1);
+        FeatureStructure fsVal2 = fs2.getFeatureValue(feat2);
+        assertFsEqual(fsVal1, fsVal2);
+      }
+    }
+  }
+ 
+}

Propchange: uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/cas_data/impl/CasComparerViewChange.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/util/CasCopierTest.java
URL: http://svn.apache.org/viewvc/uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/util/CasCopierTest.java?rev=1494286&r1=1494285&r2=1494286&view=diff
==============================================================================
--- uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/util/CasCopierTest.java (original)
+++ uima/uimaj/trunk/uimaj-core/src/test/java/org/apache/uima/util/CasCopierTest.java Tue Jun 18 20:25:39 2013
@@ -35,6 +35,7 @@ import org.apache.uima.cas.impl.LowLevel
 import org.apache.uima.cas.impl.XCASDeserializer;
 import org.apache.uima.cas.text.AnnotationFS;
 import org.apache.uima.cas_data.impl.CasComparer;
+import org.apache.uima.cas_data.impl.CasComparerViewChange;
 import org.apache.uima.resource.metadata.FsIndexDescription;
 import org.apache.uima.resource.metadata.TypeDescription;
 import org.apache.uima.resource.metadata.TypeSystemDescription;
@@ -159,6 +160,18 @@ public class CasCopierTest extends TestC
 
     // verify copy
     CasComparer.assertEquals(srcCas, destCas);
+    
+    // do the copy to a different view
+    // create a destination CAS
+    destCas = CasCreationUtils.createCas(typeSystem, new TypePriorities_impl(), indexes);
+
+    // do the copy
+    copier = new CasCopier(srcCas, destCas);
+    copier.copyCasView(srcCas, "aNewView", true);
+
+    // verify copy
+    (new CasComparerViewChange(srcCas, destCas.getView("aNewView"))).assertEqualViews();
+    
   }
 
   public void testCopyFs() throws Exception {