You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@opennlp.apache.org by co...@apache.org on 2012/02/12 02:22:52 UTC

svn commit: r1243189 - /incubator/opennlp/trunk/opennlp-tools/src/main/java/opennlp/tools/util/model/BaseModel.java

Author: colen
Date: Sun Feb 12 01:22:51 2012
New Revision: 1243189

URL: http://svn.apache.org/viewvc?rev=1243189&view=rev
Log:
OPENNLP-429: Forgot to commit the BaseModel

Modified:
    incubator/opennlp/trunk/opennlp-tools/src/main/java/opennlp/tools/util/model/BaseModel.java

Modified: incubator/opennlp/trunk/opennlp-tools/src/main/java/opennlp/tools/util/model/BaseModel.java
URL: http://svn.apache.org/viewvc/incubator/opennlp/trunk/opennlp-tools/src/main/java/opennlp/tools/util/model/BaseModel.java?rev=1243189&r1=1243188&r2=1243189&view=diff
==============================================================================
--- incubator/opennlp/trunk/opennlp-tools/src/main/java/opennlp/tools/util/model/BaseModel.java (original)
+++ incubator/opennlp/trunk/opennlp-tools/src/main/java/opennlp/tools/util/model/BaseModel.java Sun Feb 12 01:22:51 2012
@@ -21,8 +21,8 @@ package opennlp.tools.util.model;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.Map;
 import java.util.Properties;
 import java.util.zip.ZipEntry;
@@ -39,7 +39,7 @@ import opennlp.tools.util.Version;
  * TODO:
  * Provide sub classes access to serializers already in constructor
  */
-public abstract class BaseModel {
+public abstract class BaseModel implements ArtifactProvider {
 
   protected static final String MANIFEST_ENTRY = "manifest.properties";
   
@@ -57,13 +57,22 @@ public abstract class BaseModel {
       new HashMap<String, ArtifactSerializer>();
 
   protected final Map<String, Object> artifactMap;
-
+  
   private final String componentName;
+
+  private HashSet<String> unloadedExtensions;
+
+  private boolean subclassSerializersInitiated = false;
+  private boolean finishedLoadingArtifacts = false;
   
   /**
-   * Initializes the current instance.
+   * Initializes the current instance. The sub-class constructor should call the methods:
+   * <li> {@link #loadArtifactSerializers()} to populate the serializers map, and
+   * <li> {@link #checkArtifactMap()} to check the artifact map is OK. <p>
+   * Not calling these methods will cause an {@link IllegalStateException}
    *
-   * @param languageCode
+   * @param componentName the component name
+   * @param languageCode the language code
    * @param manifestInfoEntries additional information in the manifest
    */
   protected BaseModel(String componentName, String languageCode, Map<String, String> manifestInfoEntries) {
@@ -78,7 +87,7 @@ public abstract class BaseModel {
     
     artifactMap = new HashMap<String, Object>();
     
-    createArtifactSerializers(artifactSerializers);
+    createBaseArtifactSerializers(artifactSerializers);
     
     Properties manifest = new Properties();
     manifest.setProperty(MANIFEST_VERSION_PROPERTY, "1.0");
@@ -95,12 +104,18 @@ public abstract class BaseModel {
     }
       
     artifactMap.put(MANIFEST_ENTRY, manifest);
+    finishedLoadingArtifacts = true;
   }
 
   /**
-   * Initializes the current instance.
-   *
-   * @param in
+   * Initializes the current instance. The sub-class constructor should call the methods:
+   * <li> {@link #loadArtifactSerializers()} to populate the serializers map, 
+   * <li> {@link #finishLoadingArtifacts(InputStream)} to finish loading artifacts with the loaded serializers, and
+   * <li> {@link #checkArtifactMap()} to check the artifact map is OK. <p>
+   * Not calling these methods will cause an {@link IllegalStateException}
+   * 
+   * @param componentName the component name
+   * @param in the input stream containing the model
    *
    * @throws IOException
    * @throws InvalidFormatException
@@ -115,11 +130,14 @@ public abstract class BaseModel {
 
     this.componentName = componentName;
     
-    Map<String, Object> artifactMap = new HashMap<String, Object>();
-    
-    createArtifactSerializers(artifactSerializers);
+    artifactMap = new HashMap<String, Object>();
+    createBaseArtifactSerializers(artifactSerializers);
 
     final ZipInputStream zip = new ZipInputStream(in);
+    
+    // will read it in two steps, first using the known factories, latter the
+    // unknown.
+    unloadedExtensions = new HashSet<String>();
 
     ZipEntry entry;
     while((entry = zip.getNextEntry()) != null ) {
@@ -129,17 +147,60 @@ public abstract class BaseModel {
       ArtifactSerializer factory = artifactSerializers.get(extension);
 
       if (factory == null) {
-        throw new InvalidFormatException("Unkown artifact format: " + extension);
+        unloadedExtensions.add(extension);
+      } else {
+        artifactMap.put(entry.getName(), factory.create(zip));
       }
+      
+      zip.closeEntry();
+    }
 
-      artifactMap.put(entry.getName(), factory.create(zip));
+  }
+  
+  /**
+   * Loads the artifact serializers. Should be called in sub-class constructor
+   */
+  protected void loadArtifactSerializers() {
+    if (!subclassSerializersInitiated)
+      createArtifactSerializers(artifactSerializers);
+    subclassSerializersInitiated = true;
+  }
 
-      zip.closeEntry();
+  /**
+   * Finish loading the artifacts now that it knows all serializers.
+   * <p>
+   * Should be called while loading a model from serialized file.
+   */
+  protected void finishLoadingArtifacts(InputStream in)
+      throws InvalidFormatException, IOException {
+    finishedLoadingArtifacts = true;
+    if (unloadedExtensions == null || unloadedExtensions.size() == 0) {
+      return;
     }
+    in.reset();
+    final ZipInputStream zip = new ZipInputStream(in);
+    Map<String, Object> artifactMap = new HashMap<String, Object>(
+        this.artifactMap);
+    ZipEntry entry;
+    while ((entry = zip.getNextEntry()) != null) {
+
+      String extension = getEntryExtension(entry.getName());
 
-    this.artifactMap = Collections.unmodifiableMap(artifactMap);
+      if (unloadedExtensions.contains(extension)) {
+        ArtifactSerializer factory = artifactSerializers.get(extension);
 
-    validateArtifactMap();
+        if (factory == null) {
+          throw new InvalidFormatException("Unkown artifact format: "
+              + extension);
+        } else {
+          artifactMap.put(entry.getName(), factory.create(zip));
+        }
+      }
+
+      zip.closeEntry();
+    }
+    this.unloadedExtensions = null;
+    this.artifactMap.putAll(artifactMap);
   }
 
   /**
@@ -199,9 +260,14 @@ public abstract class BaseModel {
    */
   protected void createArtifactSerializers(
       Map<String, ArtifactSerializer> serializers) {
-    serializers.putAll(createArtifactSerializers());
+    // do nothing, base artifacts are loaded by createBaseArtifactSerializers
   }
 
+  private void createBaseArtifactSerializers(
+      Map<String, ArtifactSerializer> serializers) {
+    serializers.putAll(createArtifactSerializers());
+  }
+  
   /**
    * Validates the parsed artifacts. If something is not
    * valid subclasses should throw an {@link InvalidFormatException}.
@@ -272,6 +338,9 @@ public abstract class BaseModel {
    * If the artifacts are not valid an IllegalArgumentException will be thrown.
    */
   protected void checkArtifactMap() {
+    if (!finishedLoadingArtifacts)
+      throw new IllegalStateException(
+          "The method BaseModel.finishLoadingArtifacts(..) was not called by BaseModel sub-class.");
     try {
       validateArtifactMap();
     } catch (InvalidFormatException e) {
@@ -336,6 +405,11 @@ public abstract class BaseModel {
    */
   @SuppressWarnings("unchecked")
   public final void serialize(OutputStream out) throws IOException {
+    if (!subclassSerializersInitiated) {
+      throw new IllegalStateException(
+          "The method BaseModel.loadArtifactSerializers() was not called by BaseModel subclass constructor.");
+    }
+    
     ZipOutputStream zip = new ZipOutputStream(out);
 
     for (String name : artifactMap.keySet()) {
@@ -355,4 +429,12 @@ public abstract class BaseModel {
     zip.finish();
     zip.flush();
   }
+  
+  @SuppressWarnings("unchecked")
+  public <T> T getArtifact(String key) {
+    Object artifact = artifactMap.get(key);
+    if(artifact == null)
+      return null;
+    return (T) artifact;
+  }
 }