14 Replies Latest reply: Sep 9, 2010 10:28 PM by 712739 RSS

    Problem persisting a @Persistent class

    788289
      I am getting an error saying that
      Class com.sleepycat.persist.impl.ReflectionAccessor can not access a member of class FooBarBar with modifiers "public" UNEXPECTED_EXCEPTION: Unexpected internal Exception, may have side effects.
      However, class FooBarBar doesn't have any public fields (a super-class has a private field, which is marked @NotPersistent)
      This is roughly the class hierarchy for class FooBarBar
      @Persistent
      class Foo {
      
           @NotPersistent
           private ANonEntityNonPersistentClass field1 = null;
           
           public ANonEntityNonPersistentClass getField1(){
                if (field1==null){
                     someStaticMethod.getInstance();
                }
           }
      }
      
      @Persistent
      public class FooBar
           extends Foo{
           
           // NO fields
           
           public FooBar{
                super();
           }
      
                     // some public methods
      }
      
      @Persistent
      public class FooBarBar
           extends FooBar{
           
           // NO fields
           
           public FooBarBar{
                super();
           }
      // some public methods
      }
        • 1. Re: Problem persisting a @Persistent class
          788289
          Sorry -- hit "send" too soon

          I am using BDB je 4.0.103

          Would appreciate any help/suggestions

          thanks
          • 2. Re: Problem persisting a @Persistent class
            712739
            Hi, Sheila,

            I cannot reproduce such error in my sandbox using your class hierarchy.

            So, can you provide more information about this error, including:
            1. The whole and exact error messages or exception messages, not just a sentence you posted before;
            2. How you want to persist the @Persistent class FooBarBar. I have tried two ways, one is using FooBarBar class as a member of an @Entity class, one is let an @Entity class extend from FooBarBar class. Then I persist this @Entity class, and no any error.

            After you provide more information, I will do futher investigation.

            Thanks.

            Eric
            Berkeley DB, Java Edition
            Oracle
            • 3. Re: Problem persisting a @Persistent class
              788289
              Eric,

              Here is the complete message:
              failed to execute identifier
              org.jhove2.core.JHOVE2Exception: failed to execute identifier
                   at org.jhove2.module.identify.IdentifierCommand.execute(IdentifierCommand.java:121)
                   at org.jhove2.core.JHOVE2.characterize(JHOVE2.java:180)
                   at org.jhove2.app.JHOVE2CommandLine.main(JHOVE2CommandLine.java:179)
              Caused by: org.jhove2.core.JHOVE2Exception: Could not persist Module
                   at org.jhove2.persist.berkeleydpl.BerkeleyDbBaseModuleAccessor.persistModule(BerkeleyDbBaseModuleAccessor.java:40)
                   at org.jhove2.persist.berkeleydpl.BerkeleyDbSourceAccessor.addModule(BerkeleyDbSourceAccessor.java:110)
                   at org.jhove2.core.source.AbstractSource.addModule(AbstractSource.java:219)
                   at org.jhove2.module.identify.IdentifierCommand.execute(IdentifierCommand.java:107)
                   ... 2 more
              Caused by: com.sleepycat.je.EnvironmentFailureException: (JE 4.0.103) java.lang.IllegalAccessException: Class com.sleepycat.persist.impl.ReflectionAccessor can not access a member of class org.jhove2.persist.berkeleydpl.BerkeleyDbIdentifierAccessor with modifiers "public" UNEXPECTED_EXCEPTION: Unexpected internal Exception, may have side effects.
                   at com.sleepycat.je.EnvironmentFailureException.unexpectedException(EnvironmentFailureException.java:286)
                   at com.sleepycat.compat.DbCompat.unexpectedException(DbCompat.java:500)
                   at com.sleepycat.persist.impl.ReflectionAccessor.newInstance(ReflectionAccessor.java:153)
                   at com.sleepycat.persist.impl.ComplexFormat.newInstance(ComplexFormat.java:513)
                   at com.sleepycat.persist.impl.RecordInput.readObject(RecordInput.java:174)
                   at com.sleepycat.persist.impl.ReflectionAccessor$ObjectAccess.read(ReflectionAccessor.java:406)
                   at com.sleepycat.persist.impl.ReflectionAccessor.readNonKeyFields(ReflectionAccessor.java:285)
                   at com.sleepycat.persist.impl.ReflectionAccessor.readNonKeyFields(ReflectionAccessor.java:273)
                   at com.sleepycat.persist.impl.ComplexFormat.readObject(ComplexFormat.java:520)
                   at com.sleepycat.persist.impl.PersistEntityBinding.readEntity(PersistEntityBinding.java:101)
                   at com.sleepycat.persist.impl.PersistEntityBinding.entryToObjectInternal(PersistEntityBinding.java:71)
                   at com.sleepycat.persist.impl.PersistEntityBinding.entryToObject(PersistEntityBinding.java:58)
                   at com.sleepycat.persist.PrimaryIndex.put(PrimaryIndex.java:387)
                   at com.sleepycat.persist.PrimaryIndex.put(PrimaryIndex.java:333)
                   at org.jhove2.persist.berkeleydpl.BerkeleyDbBaseModuleAccessor.persistModule(BerkeleyDbBaseModuleAccessor.java:37)
                   ... 5 more
              Caused by: java.lang.IllegalAccessException: Class com.sleepycat.persist.impl.ReflectionAccessor can not access a member of class org.jhove2.persist.berkeleydpl.BerkeleyDbIdentifierAccessor with modifiers "public"
                   at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:65)
                   at java.lang.reflect.Constructor.newInstance(Constructor.java:505)
                   at com.sleepycat.persist.impl.ReflectionAccessor.newInstance(ReflectionAccessor.java:151)
                   ... 17 more
              Here are the relevant classes/hierarchies
              Interface Source
                   AbstractSource (entity class)  primary key Long sourceId;
              
              Interface Module
                  Abstractclass AbstractModule (entity class)  primary key Long moduleId; secondary key Long parentSourceId, relate=MANY_TO_ONE, relatedEntity=AbstractSource.class,
                                                                                 onRelatedEntityDelete=NULLIFY)     
                      IdentiferModule  Concrete class  (persistent class)
                         which contains persistent member field of type  BerkeleyDbIdentifierAccessor
               
              
              
               BerkeleyDbIdentifierAccessor is the FooBarBar class of my simplified code in my first message
               
               Interface BerkeleyDbAccessor
                    BerkeleyDbBaseAccessor  (persistent class with non-persistent field - uses static method to popuplate from a static singleton) 
                                         @NotPersistent
                              private BerkeleyDbPersistenceManager berkeleyDbPersistenceManager = null;      // class that sets up BDB env, store, indexes, registers classes, etc, does data access thru indexes
              
                                         public BerkeleyDbPersistenceManager getBerkeleyDbPersistenceManager()
                             throws JHOVE2Exception {
                        if (berkeleyDbPersistenceManager == null){
                             berkeleyDbPersistenceManager = 
                                  (BerkeleyDbPersistenceManager) PersistenceManagerUtil.getPersistenceManagerFactory().getInstance();
                        }
                        return berkeleyDbPersistenceManager;
                            }                               
               
                    BerkeleyDbBaseModuleAccessor  (persisent class with NO fields) -- contains peristModule() method
               
                        public Module persistModule(Module module) throws JHOVE2Exception {
                             if (module != null){
                                  try{
                                       getBerkeleyDbPersistenceManager().getModuleByModuleId().put((AbstractModule) module);
                                  }
                                  catch(DatabaseException e){
                                       throw new JHOVE2Exception("Could not persist Module" , e);
                                  }
                             }
                             return module;
                         }
                        
                     BerkeleyDbIdentifierAccessor persistent class with NO fields -- member field of Identifier Module which is to be persisted
              At the point where the exception is thrown, an IdentifierModule is being added as a child module of a Source (via setting the secondary key field parentSournceId of the IdentifierModule). The IdentifierModule is then persisted when that update to its secondary key field was maide, using the persistModule() method of the BerkeleyDbIdentifierAccessor field of the IdentifierModule itself . This is when the exception is thrown.

              Thanks so much for looking into this.

              Sheila
              • 4. Re: Problem persisting a @Persistent class
                Greybird-Oracle
                Sheila, I think we need to see the complete/unmodified source code (not the methods, but at least the fields) for all the persistent classes. Are you nesting classes without the static modifier by chance?

                --mark                                                                                                                                                                                                                                                                                                                                                                                                                                               
                • 5. Re: Problem persisting a @Persistent class
                  788289
                  Here are the classes in the BerkeleyDbAccessor hierarchy
                  public interface ModuleAccessor {
                       /**
                        * Persists the Module object (may be no-op, if ModuleAccessor is for in-memory JHOVE2)
                        * @param source Module to be persisted
                        * @return Module object that was persisted
                        * @throws JHOVE2Exception
                        */
                       public Module persistModule(Module module) throws JHOVE2Exception;
                       /**
                        * Retrieves persisted Module object dereferenced via a key
                        * @param key Object by which persisted Module is dereferenced and retrieved
                        * @return Module object corresponding to key
                        * @throws JHOVE2Exception
                        */
                       public Module retrieveModule(Object key) throws JHOVE2Exception;
                       
                  }
                  
                  
                  public interface BerkeleyDbAccessor {
                  
                       /**
                        * Source and Module accessors are persistent; the Persistence Manager, with all the BerkeleyDB-related fields,
                        * cannot be persisted.  Access to the Persistence Manager is via this method, which uses a static
                        * utility method to access the BerkeleyDbPersistenceManagerFactory to access its (singleton) instance
                        * of the BerkeleyDbPersistenceManager.
                        * @return the berkeleyDbPersistenceManager
                        */
                       public BerkeleyDbPersistenceManager getBerkeleyDbPersistenceManager() 
                       throws JHOVE2Exception;
                  }
                  
                  @Persistent
                  public class BerkeleyDbBaseAccessor implements BerkeleyDbAccessor {
                       @NotPersistent
                       private BerkeleyDbPersistenceManager berkeleyDbPersistenceManager = null;
                       /* (non-Javadoc)
                        * @see org.jhove2.persist.berkeleydpl.BerkeleyDbAccessor#getBerkeleyDbPersistenceManager()
                        */
                       
                       public BerkeleyDbBaseAccessor(){}
                       
                       @Override
                       public BerkeleyDbPersistenceManager getBerkeleyDbPersistenceManager()
                                 throws JHOVE2Exception {
                            if (berkeleyDbPersistenceManager == null){
                                 berkeleyDbPersistenceManager = 
                                      (BerkeleyDbPersistenceManager) PersistenceManagerUtil.getPersistenceManagerFactory().getInstance();
                            }
                            return berkeleyDbPersistenceManager;
                       }
                  
                  }
                  @Persistent
                  public class BerkeleyDbBaseModuleAccessor 
                       extends BerkeleyDbBaseAccessor 
                       implements BerkeleyDbAccessor, ModuleAccessor {
                  
                       /**
                        * Constructor
                        */
                       public BerkeleyDbBaseModuleAccessor(){
                            super();
                       }
                       
                       @Override
                       public Module persistModule(Module module) throws JHOVE2Exception {
                            if (module != null){
                                 //When one of the put methods in the PrimaryIndex is called and a new key is assigned, 
                                 //the assigned value is returned to the caller via the key field of the entity object that 
                                 //is passed as a parameter
                                 try{
                                      getBerkeleyDbPersistenceManager().getModuleByModuleId().put((AbstractModule) module);
                                 }
                                 catch(DatabaseException e){
                                      throw new JHOVE2Exception("Could not persist Module" , e);
                                 }
                            }
                            return module;
                       }
                  
                       @Override
                       public Module retrieveModule(Object key) throws JHOVE2Exception {
                            Long longKey = null;
                            Module module = null;
                            if (key != null && key instanceof Long){
                                 try{
                                      module = getBerkeleyDbPersistenceManager().getModuleByModuleId().get(longKey);
                                 }
                                 catch (DatabaseException e){
                                      throw new JHOVE2Exception("Could not retrieve module for key" + key.toString(), e);
                                 }
                            }
                            return module;
                       }
                  }
                  
                  @Persistent
                  class BerkeleyDbIdentifierAccessor extends BerkeleyDbBaseModuleAccessor
                  implements IdentifierAccessor {
                  
                       public BerkeleyDbIdentifierAccessor(){
                            super();
                       }
                       /* (non-Javadoc)
                        * @see org.jhove2.persist.IdentifierAccessor#getFileSourceIdentifier(org.jhove2.module.identify.Identifier)
                        */
                       @Override
                       public FileSourceIdentifier getFileSourceIdentifier(Identifier module)
                       throws JHOVE2Exception {
                            FileSourceIdentifier fsi = null;
                            if (module != null){
                                 try{
                                      Module rModule = 
                                           this.getBerkeleyDbPersistenceManager().
                                           getFileSourceIdentifierByParentIdentifier().get(module.getModuleId());
                                      if (rModule != null){
                                           fsi = (FileSourceIdentifier)rModule;
                                      }
                                 }
                                 catch(DatabaseException e){
                                      throw new JHOVE2Exception("Unable to retrieve FileSourceIdentifier",e);
                                 }
                            }
                            return fsi;
                       }
                  Here are the classes in the Module hierarchy (IdentifierModule has BerkeleyDbIdentifierAccessor field, whose persistModule() method is invoked to persist the IdentifierModule,including its BerkeleyDbIdentifierAccessor field)
                  public interface Module
                       extends Reportable // Reportable is an Interface
                  {
                       public enum Scope {
                            Generic,
                            Specific
                       }
                       @ReportableProperty(order = 4, value = "Module developers.")
                       public List<Agent> getDevelopers();
                       @ReportableProperty(order = 7, value = "Module informative note.")
                       public String getNote();
                       @ReportableProperty(order = 2, value = "Module release date.")
                       public String getReleaseDate();
                       @ReportableProperty(order = 3, value = "Module rights statement.")
                       public String getRightsStatement();
                       @ReportableProperty(order = 5, value = "Module scope: generic or " +
                                 "specific (to a source unit.")
                       public Scope getScope();
                           @ReportableProperty(order = 8, value = "Timer info for this module.")
                           public TimerInfo getTimerInfo();
                       @ReportableProperty(order = 1, value = "Module version identifier.")
                       public String getVersion();
                       @ReportableProperty(order = 6, value = "External product wrapped by the module.")
                       public WrappedProduct getWrappedProduct();
                       public Long getModuleId();
                       public Long getParentSourceId();
                       public void setModuleId(Long moduleId);
                       public void setParentSourceId(Long parentSourceId);
                       public ModuleAccessor getModuleAccessor();
                       public void setModuleAccessor(ModuleAccessor moduleAccessor);
                  }
                  
                  @Persistent
                  public abstract class AbstractReportable
                       implements Reportable
                  {
                       protected I8R myI8R = null;
                       protected String reportableName = null;     
                       public AbstractReportable(){};
                       @Override
                       public I8R getReportableIdentifier() {
                            if (this.myI8R == null){
                                 this.myI8R = I8R.makeReportableI8R(this);
                            }
                            return this.myI8R;
                       }
                       @Override
                       @ReportableProperty(value = "Reportable name")
                       public String getReportableName(){
                            if (this.reportableName == null) {
                                 this.reportableName = this.getClass().getSimpleName();
                            }
                            return reportableName;
                       }
                       @Override
                       public void setReportableName(String name){
                            this.reportableName = name;
                       }     
                  }
                  
                  
                  @Entity
                  public abstract class AbstractModule
                       extends AbstractReportable
                       implements Module 
                   {
                       @PrimaryKey(sequence="MODULE_ID")
                       protected Long moduleId;
                       
                       @SecondaryKey(relate=MANY_TO_ONE, relatedEntity=AbstractSource.class,
                                 onRelatedEntityDelete=NULLIFY)               
                       protected Long parentSourceId;
                       
                       protected ModuleAccessor moduleAccessor;
                            
                  
                       protected List<Agent> developers;
                       protected String name;
                       protected String note;
                       protected String releaseDate;
                       protected String rights;
                       protected Scope scope;
                       protected String version;
                       protected WrappedProduct wrappedProduct;
                       protected TimerInfo timerInfo;
                       
                       public AbstractModule(String version, String release, String rights,
                                               Scope scope, ModuleAccessor moduleAccessor)
                       {     
                            super();
                            this.version     = version;
                            this.releaseDate = release;
                            this.rights      = rights;
                            this.scope        = scope;
                            
                            this.developers  = new ArrayList<Agent>();          
                            this.timerInfo   = new TimerInfo();
                            this.name        = this.getClass().getSimpleName();
                            this.moduleAccessor = moduleAccessor;
                       }
                  
                       public AbstractModule(){
                            super();
                       }
                  
                       @Override
                       public List<Agent> getDevelopers() {
                            return this.developers;
                       }
                  
                       @Override
                       public String getNote() {
                            return this.note;
                       }
                  
                       @Override
                       public String getReleaseDate() {
                            return this.releaseDate;
                       }
                  
                       @Override
                       public String getRightsStatement() {
                            return this.rights;
                       }
                       @Override
                       public Scope getScope() {
                            return this.scope;
                       }
                  
                       @Override
                       public String getVersion() {
                            return this.version;
                       }
                  
                       public void setDevelopers(List<Agent> developers) {
                            this.developers = developers;
                       }
                  
                       public void setNote(String note) {
                            this.note = note;
                       }
                       
                       @Override
                       public WrappedProduct getWrappedProduct() {
                            return this.wrappedProduct;
                       }
                       
                       public void setWrappedProduct(WrappedProduct product) {
                            this.wrappedProduct = product;
                       }
                       
                       /** Get module timer information.
                        * @return Module timer information
                        */
                       @Override
                       public TimerInfo getTimerInfo() {
                            return timerInfo;
                       }
                       @Override
                       public Long getModuleId() {
                            return moduleId;
                       }
                       @Override
                       public Long getParentSourceId() {
                            return parentSourceId;
                       }
                       @Override
                       public void setModuleId(Long moduleId) {
                            this.moduleId = moduleId;
                       }
                       @Override
                       public void setParentSourceId(Long parentSourceId) {
                            this.parentSourceId = parentSourceId;
                       }
                       @Override
                       public ModuleAccessor getModuleAccessor() {
                            return moduleAccessor;
                       }
                       @Override
                       public void setModuleAccessor(ModuleAccessor moduleAccessor) {
                            this.moduleAccessor = moduleAccessor;
                       }
                  }
                  public interface Identifier
                       extends Module
                  {
                       public Set<FormatIdentification> identify(JHOVE2 jhove2, Source source)
                                 throws IOException, JHOVE2Exception;
                       public FileSourceIdentifier getFileSourceIdentifier() throws JHOVE2Exception;
                  
                       public FileSourceIdentifier setFileSourceIdentifier(FileSourceIdentifier fileSourceIdentifier) throws JHOVE2Exception;
                  
                  }
                  @Persistent
                  public class IdentifierModule
                       extends AbstractModule 
                       implements Identifier
                  {
                       public static final String VERSION = "2.0.0";
                       public static final String RELEASE = "2010-09-10";
                       public static final String RIGHTS = "Copyright 2010 by The Regents of the University of California, "
                            + "Ithaka Harbors, Inc., and The Board of Trustees of the Leland "
                            + "Stanford Junior University. "
                            + "Available under the terms of the BSD license.";
                  
                       public IdentifierModule() {
                            super(VERSION, RELEASE, RIGHTS, Scope.Generic, null);
                       }
                  
                  
                       public IdentifierModule(IdentifierAccessor identifierAccessor) {
                            super(VERSION, RELEASE, RIGHTS, Scope.Generic, identifierAccessor);
                       }
                  
                       @Override
                       public Set<FormatIdentification> identify(JHOVE2 jhove2, Source source)
                            throws IOException, JHOVE2Exception
                       {
                            Set<FormatIdentification> presumptiveFormatIDs = 
                                 new TreeSet<FormatIdentification>();
                            if (source instanceof ClumpSource) {
                                 /* ClumpSources are only created when identified as instances
                                  * of a particular clump format, so should have identifications
                                  * already.
                                  */
                                 ;
                            }
                            else if (source instanceof DirectorySource ||
                                       source instanceof ZipDirectorySource) {
                                 FormatIdentification id =
                                      new FormatIdentification(new I8R(I8R.JHOVE2_PREFIX + "/" +
                                                                         I8R.JHOVE2_FORMAT_INFIX +
                                                                         "/directory"),
                                                                Confidence.PositiveSpecific,
                                                                this.getReportableIdentifier());
                                 presumptiveFormatIDs.add(id);
                            }
                            else if (source instanceof FileSetSource) {
                                 FormatIdentification id =
                                      new FormatIdentification(new I8R(I8R.JHOVE2_PREFIX + "/" +
                                                                         I8R.JHOVE2_FORMAT_INFIX +
                                                                         "/file-set"),
                                                                Confidence.PositiveSpecific,
                                                                this.getReportableIdentifier());
                                 presumptiveFormatIDs.add(id);
                            }
                            else {   /* Identify file source unit. */                    
                                 TimerInfo timer = this.getFileSourceIdentifier().getTimerInfo();
                                 timer.setStartTime();
                                 try {
                                      Set<FormatIdentification> formats =
                                           this.getFileSourceIdentifier().identify(jhove2, source);
                                      presumptiveFormatIDs.addAll(formats);
                                 }
                                 finally {
                                      timer.setEndTime();
                                 }
                            }
                            return presumptiveFormatIDs;
                       }
                  
                  
                       @Override
                       public FileSourceIdentifier getFileSourceIdentifier()  
                       throws JHOVE2Exception{
                            if (this.getModuleAccessor()==null){
                                 throw new JHOVE2Exception("IdentifierAccessor is null");
                            }
                            IdentifierAccessor ia = (IdentifierAccessor) this.getModuleAccessor();
                            return ia.getFileSourceIdentifier(this);
                       }
                  
                       /**
                        * Set file source identifier module.
                        * @param fileSourceIdentifier File source identifier module
                        */
                       public FileSourceIdentifier setFileSourceIdentifier(FileSourceIdentifier fileSourceIdentifier)  
                       throws JHOVE2Exception{
                            if (this.getModuleAccessor()==null){
                                 throw new JHOVE2Exception("IdentifierAccessor is null");
                            }
                            IdentifierAccessor ia = (IdentifierAccessor) this.getModuleAccessor();
                            return ia.setFileSourceIdentifier(this, fileSourceIdentifier);
                       }
                  
                  }
                  
                  public interface FileSourceIdentifier
                       extends Module
                  {
                       public Set<FormatIdentification> identify(JHOVE2 jhove2, Source source)
                                 throws IOException, JHOVE2Exception;
                  
                       public Long getParentIdentifierId();
                       public void setParentIdentifierId(Long id);
                  }
                  More classes in next message -- I'm exeeding themessage length limit

                  Many thanks for giving thought to this.

                  Sheila
                  • 6. Re: Problem persisting a @Persistent class
                    788289
                    @Persistent
                    public class DROIDIdentifier
                         extends AbstractModule
                         implements FileSourceIdentifier
                    {
                    
                         public static final String VERSION = "2.0.0";
                    
                         public static final String RELEASE = "2010-09-10";
                    
                         public static final String RIGHTS = "Copyright 2010 by The Regents of the University of California, "
                              + "Ithaka Harbors, Inc., and The Board of Trustees of the Leland "
                              + "Stanford Junior University. "
                              + "Available under the terms of the BSD license.";
                         
                         @SecondaryKey(relate=ONE_TO_ONE, relatedEntity=AbstractModule.class,
                                   onRelatedEntityDelete=NULLIFY)
                         protected Long parentIdentifierId;
                         
                         public static final String DROID_NAME = "DROID (Digital Record Object Identification)";
                    
                         public static final String PUIDMAP_BEANNAME = "DroidMap";
                    
                         public static final String JHOVE2BEANMAP_BEANNAME = "FormatBeanMap";
                    
                         protected Message fileNotIdentifiedMessage;  // Message is a persistent class
                    
                         protected Message fileNotRunMessage;
                    
                         protected Message fileErrorMessage;
                    
                         private String configurationFileName = null;
                         
                         private String signatureFileName = null;
                         
                    
                         @NotPersistent
                         private static ConcurrentMap<String, String> puidToJhoveId;
                    
                         @NotPersistent
                         private static ConfigFile cachedConfigFile = null;
                    
                         @NotPersistent
                         private static FFSignatureFile cachedSigFile = null;
                    
                         /**Instantiate a new <code>DROIDIdentifier</code> module that wraps DROID.
                          * @throws JHOVE2Exception 
                          */
                         public DROIDIdentifier()
                              throws JHOVE2Exception
                         {
                              this(null, null, null);
                         }
                         
                         /**Instantiate a new <code>DROIDIdentifier</code> module that wraps DROID.
                          * @param moduleAccessor persistence manager
                          * @throws JHOVE2Exception 
                          */
                         public DROIDIdentifier(ModuleAccessor moduleAccessor)
                              throws JHOVE2Exception
                         {
                              this(null, null, moduleAccessor);
                         }
                         
                         /**Instantiate a new <code>DROIDIdentifier</code> module that wraps DROID.
                          * @param configFileName path to DROID configuration file
                          * @param sigFileName path to DROID signature file
                          * @param moduleAccessor persistence manager
                          * @throws JHOVE2Exception 
                          */
                         public DROIDIdentifier(String configFileName, String sigFileName, 
                                   ModuleAccessor moduleAccessor)
                              throws JHOVE2Exception
                         {
                              super(VERSION, RELEASE, RIGHTS, Scope.Generic, moduleAccessor);
                              this.setConfigFileName(configFileName);
                              this.setSigFileName(sigFileName);
                         }
                         
                         /**
                          * Presumptively identify the format of a source unit.
                          * 
                          * @param jhove2
                          *            JHOVE2 framework
                          * @param source
                          *            Source unit
                          * @return Set of presumptive format identifications
                          * @throws IOException
                          *             I/O exception encountered identifying the source unit
                          * @throws JHOVE2Exception
                          */
                         @Override
                         public Set<FormatIdentification> identify(JHOVE2 jhove2, Source source)
                              throws IOException, JHOVE2Exception
                         {
                              DROIDWrapper droid = new DROIDWrapper();
                              Set<FormatIdentification> presumptiveFormatIds =
                                   new TreeSet<FormatIdentification>();
                              try {
                                   ConfigFile configFile = getCachedConfigFile(this.getConfigurationFile());
                                   FFSignatureFile sigFile = getCachedSignatureFile(configFile, this.getSignatureFile());
                                   droid.setConfigFile(configFile);
                                   droid.setSigFile(sigFile);
                                   IdentificationFile idf = droid.identify(source);
                                   boolean matchFound = this.matchFound(idf, jhove2);
                                   if (matchFound){
                                        String msgText = idf.getWarning();                    
                                        Message idWarningMessage = null;
                                        if (msgText != null && msgText.length()>0) {
                                             Object [] messageParms = new Object []{msgText};
                                             idWarningMessage = new Message(Severity.WARNING,
                                                       Context.OBJECT,
                                                       "org.jhove2.module.identify.DROIDIdentifier.identify.idWarningMessage",
                                                       messageParms, jhove2.getConfigInfo());
                                        }
                                        for (int i=0; i<idf.getNumHits(); i++){          
                                             ArrayList<Message> idMessages = new ArrayList<Message>();
                                             ArrayList<Message> unmatchedPUIDMessages = 
                                                  new ArrayList<Message>();
                                             Message hitWarningMsg = null;
                                             if (idWarningMessage != null){
                                                  idMessages.add(idWarningMessage);
                                             }
                                             FileFormatHit ffh = idf.getHit(i);
                                             String hitWarning = ffh.getHitWarning();
                                             if (hitWarning != null && hitWarning.length()>0) {
                                                  Object[]messageParms = new Object[]{hitWarning};
                                                  hitWarningMsg = new Message(Severity.WARNING,
                                                            Context.OBJECT,
                                                            "org.jhove2.module.identify.DROIDIdentifier.identify.hitWarningMsg",
                                                            messageParms, jhove2.getConfigInfo());
                                                  idMessages.add(hitWarningMsg);
                                             }
                                             FileFormat ff = ffh.getFileFormat();                    
                                             String puid = ff.getPUID();
                                             I8R droidId = new I8R(puid, I8R.Namespace.PUID);
                                             Confidence jhoveConfidence = this.getJHOVE2Confidence(ffh);     
                                             // look up the JHOVE2 format id corresponding to DROID format id (PUID)
                                             String jhoveFormatId = null;
                                             if (! getPUIDtoJ2ID(jhove2).containsKey(puid)){
                                                  // if there is no match, attach an ERROR message to the FormatIdentification, 
                                                  // and use the default JHOVE2 format
                                                  Object[]messageParms = new Object[]{puid};
                                                  Message missingPuid = new Message(Severity.ERROR,
                                                            Context.PROCESS,
                                                            "org.jhove2.module.identify.DROIDIdentifier.identify.missingPUID",
                                                            messageParms, jhove2.getConfigInfo());
                                                  unmatchedPUIDMessages.add(missingPuid);
                                             }
                                             else {
                                                  jhoveFormatId = getPUIDtoJ2ID(jhove2).get(puid);     
                                             }
                                             idMessages.addAll(unmatchedPUIDMessages);
                                             I8R jhoveId = null;
                                             if (jhoveFormatId != null) {
                                                  jhoveId = new I8R(jhoveFormatId);
                                             }
                                             FormatIdentification fi =
                                                  new FormatIdentification(jhoveId, jhoveConfidence,
                                                                            this.getReportableIdentifier(),
                                                                            droidId, idMessages);
                                             presumptiveFormatIds.add(fi);                         
                                        }
                                   }
                              }
                              catch (IOException e) {
                                   throw e;
                              }
                              catch (Exception ex) {
                                   throw new JHOVE2Exception("Failure running DROID " + ex.getMessage(),ex);
                              }
                              return presumptiveFormatIds;
                         }
                    
                         /**
                          * If DROID config file has not yet been parsed, parse and return it;
                          * Otherwise simply returns parsed config file
                          * @param configFilePath path to DROID config file
                          * @return parsed config file object
                          * @throws Exception
                          */
                         private static synchronized ConfigFile getCachedConfigFile(String configFilePath)
                              throws Exception
                         {
                              if (cachedConfigFile == null) {
                                   cachedConfigFile = DROIDWrapper.parseConfigFile(configFilePath);
                              }
                              return cachedConfigFile;
                         }
                    
                         /**
                          * If DROID signature file has not yet been parsed, parses and returns it;
                          * Otherwise, just returns parsed signature file
                          * @param configFile  parsed DROID config file object
                          * @param sigFilePath  path to DROID signature file
                          * @return parsed signature file contents
                          * @throws Exception
                          */
                         private static synchronized FFSignatureFile getCachedSignatureFile(ConfigFile configFile,
                                                                                              String sigFilePath)
                              throws Exception
                         {
                              if (cachedSigFile == null) {
                                   cachedSigFile = DROIDWrapper.parseSignatureFile(configFile,
                                                                                            sigFilePath);
                              }
                              return cachedSigFile;
                         }
                    
                        /**
                         * Return the name of the configuration file.
                         * @return Configuration file name
                         */
                        public String getConfigurationFileName() {
                            return configurationFileName;
                        }
                    
                        /** Get DROID configuration file path.
                         * @return DROID configuration file path
                         * @throws JHOVE2Exception 
                         */
                        @ReportableProperty(order = 1, value = "DROID configuration file path.")
                        public String getConfigurationFile()
                            throws JHOVE2Exception
                        {
                            String path = FeatureConfigurationUtil.getFilePathFromClasspath(this.getConfigurationFileName(), "DROID config file");
                            return path;
                        }
                    
                        /**
                         * Get DROID File Not Found message.
                         * 
                         * @return File Not Found message
                         */
                        @ReportableProperty(order = 13, value = "DROID File Not Identified Message")
                        public Message getFileNotIdentifiedMessage() {
                            return this.fileNotIdentifiedMessage;
                        }
                        
                        /**
                         * Get DROID File Not run message.
                         * 
                         * @return File Not run message
                         */
                        @ReportableProperty(order = 14, value = "DROID File Not Run Message")
                        public Message getFileNotRunMessage() {
                            return this.fileNotRunMessage;
                        }
                        
                        /**
                         * Get DROID File error message.
                         * 
                         * @return File error message
                         */
                        @ReportableProperty(order = 15, value = "DROID File Error Message.")
                        public Message getFileErrorMessage() {
                            return this.fileErrorMessage;
                        }
                        
                        /**
                         * Map from DROID confidence levels to JHOVE2 confidence levels
                         * @param ffh File format hit containing DROID confidence level
                         * @return JHOVE2 confidence level for this identifier
                         */
                        protected Confidence getJHOVE2Confidence(FileFormatHit ffh) {
                            int droidConfidence = ffh.getHitType();
                            Confidence jhoveConfidence;
                            switch (droidConfidence){
                            case JHOVE2IAnalysisController.HIT_TYPE_POSITIVE_SPECIFIC:
                                jhoveConfidence = Confidence.PositiveSpecific;
                                break;
                            case JHOVE2IAnalysisController.HIT_TYPE_POSITIVE_GENERIC_OR_SPECIFIC:
                                jhoveConfidence = Confidence.PositiveGeneric;
                                break;
                            case JHOVE2IAnalysisController.HIT_TYPE_POSITIVE_GENERIC:
                                jhoveConfidence = Confidence.PositiveGeneric;
                                break;
                            case JHOVE2IAnalysisController.HIT_TYPE_TENTATIVE:
                                jhoveConfidence = Confidence.Tentative;
                                break;
                            default:
                                jhoveConfidence = Confidence.Negative;
                            }   
                            return jhoveConfidence;
                        }
                    
                        /**
                         * Gets the mapping from DROID PUID to JHOVE2 Format Identifier. 
                         * Initializes the static map on first invocation.
                         * 
                         * @return DROID PUID to JHOVE2 Format Identifier map
                         * @throws JHOVE2Exception
                         */
                        public static ConcurrentMap<String,String> getPUIDtoJ2ID(JHOVE2 jhove2)
                            throws JHOVE2Exception
                        {
                            if (puidToJhoveId == null){
                                 puidToJhoveId = jhove2.getConfigInfo().getFormatAliasIdsToJ2Ids(I8R.Namespace.PUID);
                            }
                            return puidToJhoveId;
                        }
                     
                        /** Get DROID signature file path.
                         * @return DROID signature file path
                         * @throws JHOVE2Exception 
                         */
                        @ReportableProperty(order = 2, value = "DROID signature file path.")
                        public String getSignatureFile() throws JHOVE2Exception {
                            String path = FeatureConfigurationUtil.getFilePathFromClasspath(this.getSignatureFileName(), "DROID signature file");
                            return path;
                        }
                    
                        /**
                         * Return the name of the signature file
                         * @return the signatureFileName
                         */
                        public String getSignatureFileName() {
                            return signatureFileName;
                        }
                     
                         /**
                          * Checks DROID file classification codes to see if DROID was able to match file
                          * NOTE:  SIDE EFFECTS:  if there are errors, or if no identifier can be made, or
                          *                       if DROID returns warning message, this method populates 
                          *                       the relevant Message member of this object instance
                          * @param idf DROID {@link uk.gov.nationalarchives.droid.IdentificationFile} object
                          * @param jhove2 
                          * @return true if DROID able to identify file; otherwise false
                          * @throws JHOVE2Exception 
                          */
                         protected boolean matchFound(IdentificationFile idf, JHOVE2 jhove2)
                              throws JHOVE2Exception
                         {
                              boolean matchFound = false;
                              int classification = idf.getClassification();
                              String msgText = null;
                              switch (classification){
                              case JHOVE2IAnalysisController.FILE_CLASSIFICATION_NOHIT:
                                   msgText = idf.getWarning();
                                   if (msgText==null){
                                        msgText = new String("");
                                   }
                                   Object[]messageParms = new Object[]{msgText};
                                   this.fileNotIdentifiedMessage = new Message(Severity.WARNING,
                                             Context.OBJECT,
                                             "org.jhove2.module.identify.DROIDIdentifier.fileNotIdentifiedMessage",
                                             messageParms, jhove2.getConfigInfo());
                                   break;
                              case JHOVE2IAnalysisController.FILE_CLASSIFICATION_NOTCLASSIFIED:
                                   msgText = idf.getWarning();
                                   if (msgText==null){
                                        msgText = new String("");
                                   }
                                   messageParms = new Object[]{msgText};
                                   this.fileNotRunMessage = new Message(Severity.ERROR,
                                             Context.PROCESS,
                                             "org.jhove2.module.identify.DROIDIdentifier.fileNotRunMessage",
                                             messageParms, jhove2.getConfigInfo());
                                   break;
                              case JHOVE2IAnalysisController.FILE_CLASSIFICATION_ERROR:
                                   msgText = idf.getWarning();
                                   if (msgText==null){
                                        msgText = new String("");
                                   }
                                   messageParms = new Object[]{msgText};
                                   this.fileErrorMessage = new Message(Severity.ERROR,
                                             Context.PROCESS,
                                             "org.jhove2.module.identify.DROIDIdentifier.fileErrorMessage",
                                             messageParms, jhove2.getConfigInfo());
                                   break;
                              default:
                                   matchFound = true;
                                   break;
                              }// end switch
                              return matchFound;
                         }
                    
                    
                         /** Set File Error message.
                          * @param fileErrorMessage File Error message
                          */
                         public void setFileErrorMessage(Message fileErrorMessage) {
                              this.fileErrorMessage = fileErrorMessage;
                         }
                         
                         /** Set File Not Identified message.
                          * @param fileNotIdentifiedMessage File Not Identified message
                          */
                         public void setFileNotIdentifiedMessage(Message fileNotIdentifiedMessage) {
                              this.fileNotIdentifiedMessage = fileNotIdentifiedMessage;
                         }
                    
                         /** Set File Not Run message.
                          * @param fileNotRunMessage File Not Run message
                          */
                         public void setFileNotRunMessage(Message fileNotRunMessage) {
                              this.fileNotRunMessage = fileNotRunMessage;
                         }
                    
                         /**
                          * Set the name of the config file
                          * @param configurationFileName the configurationFileName to set
                          */
                         public void setConfigFileName(String configFileName) {
                              this.configurationFileName = configFileName;
                         }
                    
                         /**
                          * Set the name of the signature file
                          * @param signatureFileName the signatureFileName to set
                          */
                         public void setSigFileName(String sigFileName) {
                              this.signatureFileName = sigFileName;
                         }
                    
                         @Override
                         public Long getParentIdentifierId() {
                              return this.parentIdentifierId;
                         }
                    
                         @Override
                         public void setParentIdentifierId(Long id) {
                              this.parentIdentifierId = id;
                         }
                    
                    
                    }
                    @Persistent
                    public class Message {
                         /** Message contexts. */
                         public enum Context {
                              PROCESS, OBJECT
                         }
                         /** Message severities. */
                         public enum Severity {
                              ERROR, WARNING, INFO
                         }
                         /** Message code. */
                         protected String messageCode;
                    
                         /** Localized Message Text */
                         protected String localizedMessageText;
                    
                         /** Message context. */
                         protected Context context;
                    
                         /** Message severity. */
                         protected Severity severity;
                    
                         /** Message Locale. */
                         protected Locale locale;
                         
                         protected ConfigInfo configInfo;
                    
                         /** Default Locale */
                         private static Locale defaultLocale;
                    
                              static {
                                   defaultLocale = Locale.getDefault();
                              }
                    
                         @SuppressWarnings("unused")
                         private Message() throws JHOVE2Exception{
                              this(null, null, null, null, null, null);
                         }
                         /**
                          * Instantiate a new Localized <code>Message</code>.
                          * 
                          * @param severity
                          *            Message severity
                          * @param context
                          *            Message context
                          * @param messageCode
                          *            Key to message text in localized property file
                          * @param configInfo 
                          * @throws JHOVE2Exception 
                          */
                         public Message(Severity severity, Context context, String messageCode, ConfigInfo configInfo)
                              throws JHOVE2Exception
                         {
                              this(severity, context, messageCode, new Object[0], defaultLocale, configInfo);
                         }
                         
                         /**
                          * Instantiate a new Localized <code>Message</code>.
                          * 
                          * @param severity
                          *            Message severity
                          * @param context
                          *            Message context
                          * @param messageCode
                          *            Key to message text in localized property file
                          * @param messageArgs
                          *                Arguments to message format template
                          * @param configInfo 
                          *            ConfigInfo containing method to localize method text
                          * @throws JHOVE2Exception
                          */
                         public Message(Severity severity, Context context, String messageCode,
                                          Object[] messageArgs, ConfigInfo configInfo) 
                              throws JHOVE2Exception
                         {
                              this(severity, context, messageCode, messageArgs, defaultLocale, configInfo);
                         }
                    
                         /**
                          * Instantiate a new Localized <code>Message</code>.
                          * 
                          * @param severity
                          *            Message severity
                          * @param context
                          *            Message context
                          * @param messageCode
                          *            Key to message text in localized property file
                          * @param messageArgs
                          *                Arguments to message format template
                          * @param locale
                          *                  Locale for message text
                          * @param configInfo TODO
                          * @throws JHOVE2Exception
                          */
                         public Message(Severity severity, Context context, String messageCode, 
                                          Object[] messageArgs, Locale locale, ConfigInfo configInfo)
                              throws JHOVE2Exception
                         {
                              this.severity = severity;
                              this.context = context;
                              this.locale = locale;
                              this.messageCode = messageCode;
                              this.configInfo = configInfo;
                              this.localizedMessageText = this.localizeMessageText(messageCode, messageArgs, locale);
                         }
                    
                         /**
                          * Resolves message code and produces localized message text
                          * @param messageCode
                          *            Key to message text in localized property file
                          * @param messageArgs
                          *                  Arguments to message format template
                          * @param locale
                          *             Locale for message text
                          * @return  
                          *         Localized formatted message text
                          * @throws JHOVE2Exception
                          */
                         protected String localizeMessageText(String messageCode, Object[] messageArgs,
                                                                Locale locale) 
                              throws JHOVE2Exception
                         {
                              String localizedMessage = null;
                              localizedMessage = this.getConfigInfo().getLocalizedMessageText(messageCode, 
                                        messageArgs, locale);
                              return localizedMessage;
                         }
                    
                         /** Get message context.
                          * @return Message context
                          */
                         public Context getContext() {
                              return context;
                         }
                    
                         /** Get localized message text.
                          * @return Localized message text
                          */
                         public String getLocalizedMessageText() {
                              return localizedMessageText;
                         }
                    
                         /** Get message code.
                          * @return Message code
                          */
                         public String getMessageCode() {
                              return messageCode;
                         }
                    
                         /** Get message severity
                          * @return Message severity
                          */
                         public Severity getSeverity() {
                              return severity;
                         }
                    
                         /** Set message context.
                          * @param context Message context
                          */
                         public void setContext(Context context) {
                              this.context = context;
                         }
                    
                         /** Set localized message text.
                          * @param localizedMessageText Localized message text
                          */
                         public void setLocalizedMessageText(String localizedMessageText) {
                              this.localizedMessageText = localizedMessageText;
                         }
                         
                         /** Set message code.
                          * @param messageCode Message code
                          */
                         public void setMessageCode(String messageCode) {
                              this.messageCode = messageCode;
                         }
                    
                         /** Set message severity.
                          * @param severity Message severity
                          */
                         public void setSeverity(Severity severity) {
                              this.severity = severity;
                         }
                    
                         /**
                          * Get {@link java.lang.String} representation of the message.
                          */
                         @Override
                         public String toString() {
                              return "[" + this.severity + "/" + this.context + "] " + this.localizedMessageText;
                         }
                    
                         /**
                          * @return the configInfo
                          */
                         public ConfigInfo getConfigInfo() {
                              return configInfo;
                         }
                    
                         /**
                          * @param configInfo the configInfo to set
                          */
                         public void setConfigInfo(ConfigInfo configInfo) {
                              this.configInfo = configInfo;
                         }
                    }
                    
                    
                    // and you will of course recognizer the proxy for Locale
                    @Persistent(proxyFor=Locale.class)
                    public class LocalePersisentProxy implements PersistentProxy<Locale> {
                    
                        String language;
                        String country;
                        String variant;
                    
                         private LocalePersisentProxy() {}
                    
                         @Override
                         public Locale convertProxy() {
                              return new Locale(language, country, variant);
                         }
                    
                         @Override
                         public void initializeProxy(Locale object) {
                              language = object.getLanguage();
                            country = object.getCountry();
                            variant = object.getVariant();
                    
                         }
                    
                    }
                    • 7. Re: Problem persisting a @Persistent class
                      Greybird-Oracle
                      Thanks for posting the complete classes. Hopefully this will give Eric enough information to see what's happening. He will take a look at it tonight (he is in China) and reply then.
                      --
                      mark
                      • 8. Re: Problem persisting a @Persistent class
                        788289
                        Thanks so much to you both.

                        If you need to see more of, or indeed all of, the source code -- I would be happy to zip it up and send it to you - -the code is an open-source project, available under BSD License - -and we are perfectly happy to make any of it available for inspection if that would help your detective work.

                        Thanks again for the efforts you're expending.

                        Sheila
                        • 9. Re: Problem persisting a @Persistent class
                          788289
                          NB - -just realized in Souce code above, left off mutator setFileSourceIdentifier () method for BerkeleyDbIdentifierAccessor class -- here is the complete class:
                          @Persistent
                          class BerkeleyDbIdentifierAccessor extends BerkeleyDbBaseModuleAccessor
                          implements IdentifierAccessor {
                          
                               public BerkeleyDbIdentifierAccessor(){
                                    super();
                               }
                               /* (non-Javadoc)
                                * @see org.jhove2.persist.IdentifierAccessor#getFileSourceIdentifier(org.jhove2.module.identify.Identifier)
                                */
                               @Override
                               public FileSourceIdentifier getFileSourceIdentifier(Identifier module)
                               throws JHOVE2Exception {
                                    FileSourceIdentifier fsi = null;
                                    if (module != null){
                                         try{
                                              Module rModule = 
                                                   this.getBerkeleyDbPersistenceManager().
                                                   getFileSourceIdentifierByParentIdentifier().get(module.getModuleId());
                                              if (rModule != null){
                                                   fsi = (FileSourceIdentifier)rModule;
                                              }
                                         }
                                         catch(DatabaseException e){
                                              throw new JHOVE2Exception("Unable to retrieve FileSourceIdentifier",e);
                                         }
                                    }
                                    return fsi;
                               }
                          
                               /* (non-Javadoc)
                                * @see org.jhove2.persist.IdentifierAccessor#setFileSourceIdentifier(org.jhove2.module.identify.Identifier, org.jhove2.module.identify.FileSourceIdentifier)
                                */
                               @Override
                               public FileSourceIdentifier setFileSourceIdentifier(Identifier module,
                                         FileSourceIdentifier fileSourceIdentifier) throws JHOVE2Exception {
                          
                                    if (module != null && fileSourceIdentifier != null){
                                         if (module.getModuleId()== null){
                                              module = (Identifier) this.persistModule(module);
                                         }
                                         
                                         //un-link old FileSourceIdentifier
                                         FileSourceIdentifier oldFsi = this.getFileSourceIdentifier(module);
                                         if (oldFsi != null){
                                              oldFsi.setParentIdentifierId(null);
                                              oldFsi = (FileSourceIdentifier) this.persistModule(oldFsi);
                                         }
                          
                                         fileSourceIdentifier.setParentIdentifierId(module.getModuleId());
                                         fileSourceIdentifier = (FileSourceIdentifier) this.persistModule(fileSourceIdentifier);
                                    }          
                                    return fileSourceIdentifier;
                               }
                          
                          }
                          • 10. Re: Problem persisting a @Persistent class
                            788289
                            Also -- here is the data access class that manages indexes, etc.
                            public class BerkeleyDbPersistenceManager implements PersistenceManager {
                            
                                 protected EnvironmentConfig envConfig;
                                 protected StoreConfig storeConfig;
                                 protected String envHome;
                                 protected String entityStoreName;
                                 
                                 protected Environment env;
                                 protected EntityStore store;
                                 
                                 PrimaryIndex<Long, AbstractSource> sourceBySourceId;
                                 SecondaryIndex<Long, Long, AbstractSource>  sourceByParentSource;
                                 
                                 PrimaryIndex<Long, AbstractModule> moduleByModuleId;
                                 SecondaryIndex<Long, Long, AbstractModule> moduleByParentSource;
                                 SecondaryIndex<Long, Long, AbstractDisplayer> displayerByParentApp;
                                 SecondaryIndex<Long, Long, BaseFormatProfile> formatProfileByParentFormatModule;
                                 SecondaryIndex<Long, Long, AbstractCommand> commandByParentFramework;
                                 SecondaryIndex<Long, Long, GlobPathRecognizer> recognizerByParentAggrefier;
                                 SecondaryIndex<Long, Long, DROIDIdentifier> fileSourceIdentifierByParentIdentifier;
                                      
                                 public BerkeleyDbPersistenceManager() {
                                      super();
                                 }
                            
                            
                                 @Override
                                 public void initialize() throws JHOVE2Exception {
                                      File envHomeFile = new File(envHome);
                                      boolean exists = envHomeFile.exists();
                                      if (!exists){
                                           boolean couldMakeDirs = envHomeFile.mkdirs();
                                           if (!couldMakeDirs){
                                                throw new JHOVE2Exception("Could not create BerkeleyDB env home path "+
                                                          envHome);
                                           }
                                      }
                                      boolean isDir = envHomeFile.isDirectory(); 
                                      if (!isDir){
                                           throw new JHOVE2Exception("BerkeleyDB env home path " +
                                                     envHome + " is not a directory");
                                      }
                                      try{
                                           env = new Environment(envHomeFile, envConfig);               
                                           EntityModel model = new AnnotationModel();
                                           
                                           // register sub-classes for indexes
                                           model.registerClass(AbstractDisplayer.class);
                                           model.registerClass(AbstractApplication.class);
                                           model.registerClass(BaseFormatModule.class);
                                           model.registerClass(BaseFormatProfile.class);
                                           model.registerClass(JHOVE2.class);
                                           model.registerClass(AggrefierModule.class);
                                           model.registerClass(GlobPathRecognizer.class);
                                           model.registerClass(AbstractCommand.class);
                                           model.registerClass(IdentifierModule.class);
                                           model.registerClass(DROIDIdentifier.class);
                                           
                                           //register proxies
                                           model.registerClass(LocalePersisentProxy.class);
                                           model.registerClass(PatternPersistentProxy.class);
                                           
                                           storeConfig.setModel(model);                              
                                           store = new EntityStore(env,entityStoreName,storeConfig);
                                                
                                           // create indexes for Source entities
                                           sourceBySourceId = 
                                                this.getStore().getPrimaryIndex(Long.class, AbstractSource.class);               
                                           sourceByParentSource = 
                                                this.getStore().getSecondaryIndex(sourceBySourceId, Long.class, "parentSourceId");
                                           // create indesxes for Module entities
                                           moduleByModuleId = 
                                                this.getStore().getPrimaryIndex(Long.class, AbstractModule.class);
                                           moduleByParentSource =
                                                this.getStore().getSecondaryIndex(moduleByModuleId, Long.class, "parentSourceId");
                                           displayerByParentApp =
                                                this.getStore().getSubclassIndex(moduleByModuleId, AbstractDisplayer.class, Long.class, "parentAppId");
                                           formatProfileByParentFormatModule =
                                                this.getStore().getSubclassIndex(moduleByModuleId, BaseFormatProfile.class, Long.class,"formatModuleId");
                                           commandByParentFramework =
                                                this.getStore().getSubclassIndex(moduleByModuleId, AbstractCommand.class, Long.class,"jhove2ModuleId");
                                           recognizerByParentAggrefier =
                                                this.getStore().getSubclassIndex(moduleByModuleId, GlobPathRecognizer.class, Long.class, "parentAggrefierId");
                                           fileSourceIdentifierByParentIdentifier =
                                                this.getStore().getSubclassIndex(moduleByModuleId, DROIDIdentifier.class, Long.class, "parentIdentifierId");
                                      }
                                      catch (Exception e){
                                           throw new JHOVE2Exception ("Cannot initialize Berkeley DB environment", e);
                                      }
                                 }
                            
                                 @Override
                                 public void close() throws JHOVE2Exception {
                                      if (this.getStore()!= null){
                                           try {
                                                this.getStore().close();
                                           }
                                           catch(DatabaseException e){
                                                throw new JHOVE2Exception("Unable to close database Store",e);               
                                           }
                                      }
                                      if (this.getEnv()!= null){
                                           try{
                                                this.getEnv().close();
                                           }
                                           catch(DatabaseException e){
                                                throw new JHOVE2Exception("Unable to close database Environment",e);               
                                           }
                                      }
                                      return;
                                 }
                            
                                 public EnvironmentConfig getEnvConfig() {
                                      return envConfig;
                                 }
                                 public void setEnvConfig(EnvironmentConfig envConfig) {
                                      this.envConfig = envConfig;
                                 }
                            
                                 public StoreConfig getStoreConfig() {
                                      return storeConfig;
                                 }
                            
                                 public String getEnvHome() {
                                      return envHome;
                                 }
                                 public Environment getEnv() {
                                      return env;
                                 }
                                 public EntityStore getStore() {
                                      return store;
                                 }
                                 public void setStoreConfig(StoreConfig storeConfig) {
                                      this.storeConfig = storeConfig;
                                 }
                                 public void setEnvHome(String envHome) {
                                      this.envHome = envHome;
                                 }
                                 public void setEnv(Environment env) {
                                      this.env = env;
                                 }
                                 public void setStore(EntityStore store) {
                                      this.store = store;
                                 }
                                 public String getEntityStoreName() {
                                      return entityStoreName;
                                 }
                                 public void setEntityStoreName(String entityStoreName) {
                                      this.entityStoreName = entityStoreName;
                                 }
                            
                                 public PrimaryIndex<Long, AbstractSource> getSourceBySourceId() {
                                      return sourceBySourceId;
                                 }
                                 public SecondaryIndex<Long, Long, AbstractSource> getSourceByParentSource() {
                                      return sourceByParentSource;
                                 }
                            
                                 public PrimaryIndex<Long, AbstractModule> getModuleByModuleId() {
                                      return moduleByModuleId;
                                 }
                            
                                 public SecondaryIndex<Long, Long, AbstractModule> getModuleByParentSource() {
                                      return moduleByParentSource;
                                 }
                            
                                 public SecondaryIndex<Long, Long, AbstractDisplayer> getDisplayerByParentApp() {
                                      return displayerByParentApp;
                                 }
                                 public SecondaryIndex<Long, Long, BaseFormatProfile> getFormatProfileByParentFormatModule() {
                                      return formatProfileByParentFormatModule;
                                 }
                                 public SecondaryIndex<Long, Long, AbstractCommand> getCommandByParentFramework() {
                                      return commandByParentFramework;
                                 }
                                 public SecondaryIndex<Long, Long, GlobPathRecognizer> getRecognizerByParentAggrefier() {
                                      return recognizerByParentAggrefier;
                                 }
                                 public void setSourceBySourceId(
                                           PrimaryIndex<Long, AbstractSource> sourceBySourceId) {
                                      this.sourceBySourceId = sourceBySourceId;
                                 }
                                 public void setSourceByParentSource(
                                           SecondaryIndex<Long, Long, AbstractSource> sourceByParentSource) {
                                      this.sourceByParentSource = sourceByParentSource;
                                 }
                                 public void setModuleByModuleId(
                                           PrimaryIndex<Long, AbstractModule> moduleByModuleId) {
                                      this.moduleByModuleId = moduleByModuleId;
                                 }
                                 public void setModuleByParentSource(
                                           SecondaryIndex<Long, Long, AbstractModule> moduleByParentSource) {
                                      this.moduleByParentSource = moduleByParentSource;
                                 }
                                 public void setDisplayerByParentApp(
                                           SecondaryIndex<Long, Long, AbstractDisplayer> displayerByParentApp) {
                                      this.displayerByParentApp = displayerByParentApp;
                                 }
                                 public void setFormatProfileByParentFormatModule(
                                           SecondaryIndex<Long, Long, BaseFormatProfile> formatProfileByParentFormatModule) {
                                      this.formatProfileByParentFormatModule = formatProfileByParentFormatModule;
                                 }
                                 public void setCommandByParentFramework(
                                           SecondaryIndex<Long, Long, AbstractCommand> commandByParentFramework) {
                                      this.commandByParentFramework = commandByParentFramework;
                                 }
                                 public void setRecognizerByParentAggrefier(
                                           SecondaryIndex<Long, Long, GlobPathRecognizer> recognizerByParentAggrefier) {
                                      this.recognizerByParentAggrefier = recognizerByParentAggrefier;
                                 }
                                 public SecondaryIndex<Long, Long, DROIDIdentifier> getFileSourceIdentifierByParentIdentifier() {
                                      return fileSourceIdentifierByParentIdentifier;
                                 }
                                 public void setFileSourceIdentifierByParentIdentifier(
                                           SecondaryIndex<Long, Long, DROIDIdentifier> fileSourceIdentifierByParentIdentifier) {
                                      this.fileSourceIdentifierByParentIdentifier = fileSourceIdentifierByParentIdentifier;
                                 }
                            
                            }
                            • 11. Re: Problem persisting a @Persistent class
                              712739
                              Hi, Sheila,

                              Thanks for posting so much useful information.

                              I create almost the same class hierarchies in my sandbox (using JE 4.0.103) based on your posted source code. However, I can persist these persistent (especially IdentifierModule) classes, and cannot reproduce the error you met.

                              I said "almost the same" means that the persistent member fields in each class are the same, but I remove some of the methods in your provided source code, which have nothing to do with the DPL persistent process.

                              My suggestion is that can you give me your email address, so I can send you the source code which runs successfully in my sandbox. Then you can make some comparison to see why your code cannot work. I doubt that there must be some wrong modifier settings for member fields (e.g., public, static).

                              If it is not convenient for you to provide your email address here, you can contact me via email. My email is: haomian.wang at oracle.com
                              • 12. Re: Problem persisting a @Persistent class
                                788289
                                Eric - -thanks so much -- you can reach me at sheila.morrissey@ithaka.org -- I would very much appreciate looking at the code.

                                Thanks again
                                Sheila
                                • 13. Re: Problem persisting a @Persistent class
                                  788289
                                  Eric has with great perserverence got to the bottom of this -- the BerkeleyDbIdentifierAccessor class itself did NOT have a "public" access modifer. Adding the modifier fixed the problem.

                                  Disussion trail below - -many thanks from me and my team members to Eric & Co. for all the time and effort they spent on this.
                                  Hi, Sheila,
                                  
                                  On 9/8/2010 12:41 AM, Sheila M. Morrissey wrote:
                                  
                                  The problem seems to occur when I try to perist an instance of an IdentifierModule that has been persisted once before  -- here from the JUNIT test
                                  
                                                 IdentifierModule myIdModule = new IdentifierModule(new BerkeleyDbIdentifierAccessor());
                                                 myIdModule = (IdentifierModule) myIdModule.getModuleAccessor().persistModule(myIdModule);
                                                 assertEquals(1L, myIdModule.getModuleId().longValue());          
                                                 myIdModule = (IdentifierModule) myIdModule.getModuleAccessor().persistModule(myIdModule); // this throws the exception we are seeing
                                                 assertEquals(1L, myIdModule.getModuleId().longValue());
                                    
                                  I have reproduced this error in my sandbox.
                                  
                                  But I notice that there are no any modifiers for the definition of the class BerkeleyDbIdentifierAccessor. After I add "public" modification to it, which means (add the bold "public"):
                                  @Persistent
                                  public class BerkeleyDbIdentifierAccessor extends BerkeleyDbBaseModuleAccessor
                                  implements IdentifierAccessor {
                                  the test can run successfully.
                                  
                                  Is there any limitation to avoiding adding "public" modifications into BerkeleyDbIdentifierAccessor definition? If not, please adding "public" modifications into BerkeleyDbIdentifierAccessor definition to see what will happen. 
                                  
                                  Please let me know the result.
                                  
                                  Thanks.
                                  
                                  -- 
                                  Best regards.
                                  Haomian (Eric), Wang
                                  Berkeley DB, Java Edition
                                  Oracle
                                  
                                  
                                  Eric –
                                  Thanks so much - -this was the problem!!
                                  
                                  A lesson certainly to me the importance of Exception error messages –  the message from java.lang.reflect*
                                  Caused by: com.sleepycat.je.EnvironmentFailureException: (JE 4.0.103) java.lang.IllegalAccessException: Class com.sleepycat.persist.impl.ReflectionAccessor can not access a member of class org.jhove2.persist.berkeleydpl.BerkeleyDbIdentifierAccessor with modifiers "public" UNEXPECTED_EXCEPTION: Unexpected internal Exception, may have side effects 
                                  had me scrutinizing fields INSIDE BerkeleyDbIdentifierAccessor, without looking at the access modifier of the class itself.
                                  
                                  Am curious why the FIRST persist worked, but subsequent ones did n
                                  
                                  Thanks on behalf of my entire team.
                                  
                                  Sheila
                                  • 14. Re: Problem persisting a @Persistent class
                                    712739
                                    In a future release, we will have a fix that DPL can persist a non-public persistent class. For the current or previous releases, the best workaround is to make the persistent class public.