Package er.extensions.eof

Source Code of er.extensions.eof.ERXEOGlobalIDUtilities$Info

/*
* Created on 24.01.2005
*
* To change the template for this generated file go to
* Window - Preferences - Java - Code Generation - Code and Comments
*/
package er.extensions.eof;

import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.Enumeration;

import org.apache.log4j.Logger;

import com.webobjects.eoaccess.EODatabaseContext;
import com.webobjects.eoaccess.EOEntity;
import com.webobjects.eoaccess.EORelationship;
import com.webobjects.eocontrol.EOEditingContext;
import com.webobjects.eocontrol.EOEnterpriseObject;
import com.webobjects.eocontrol.EOFaultHandler;
import com.webobjects.eocontrol.EOFetchSpecification;
import com.webobjects.eocontrol.EOGlobalID;
import com.webobjects.eocontrol.EOKeyGlobalID;
import com.webobjects.eocontrol.EOObjectStoreCoordinator;
import com.webobjects.eocontrol.EOOrQualifier;
import com.webobjects.eocontrol.EOQualifier;
import com.webobjects.eocontrol.EOTemporaryGlobalID;
import com.webobjects.eocontrol._EOIntegralKeyGlobalID;
import com.webobjects.eocontrol._EOVectorKeyGlobalID;
import com.webobjects.foundation.NSArray;
import com.webobjects.foundation.NSData;
import com.webobjects.foundation.NSDictionary;
import com.webobjects.foundation.NSMutableArray;
import com.webobjects.foundation.NSTimestamp;

import er.extensions.foundation.ERXArrayUtilities;

/**
* Utilities that help with batch loading sets of global IDs.
*
* @author ak
*/
public class ERXEOGlobalIDUtilities {
 
    /** logging support */
    public static final Logger log = Logger.getLogger(ERXEOGlobalIDUtilities.class);
   
    /**
     * Unencrypts the byte array of NSData PKs so you get the process number or port,
     * host and timestamp.
     *
     * @author ak
     */
    public static class Info {

      private byte _data[];
     
      private static final int _HostIdentificationStartIndex = 0;

      private static final int _ProcessIdentificationStartIndex = 6;

      private static final int _CounterStartIndex = 10;

      private static final int _TimestampStartIndex = 12;

      private static final int _RandomStartIndex = 20;


      public Info(EOGlobalID gid) {
        if(gid instanceof EOTemporaryGlobalID) {
          _data = ((EOTemporaryGlobalID)gid)._rawBytes();
        } else if (gid instanceof EOKeyGlobalID) {
          EOKeyGlobalID keyGid = (EOKeyGlobalID)gid;
          Object value = keyGid.keyValues()[0];
          if(value instanceof NSData && keyGid.keyValues().length == 1) {
            _data = ((NSData)value)._bytesNoCopy();
          }
        }
       
        if(_data == null) {
          throw new IllegalArgumentException("This class only works with EOTemporaryGlobalID or EOKeyGlobalID with a single 24-byte data PK");
        }
      }

      private byte extractByte(int offset) {
        return _data[offset + 0];
      }

      @SuppressWarnings("cast")
    private short extractShort(int offset) {
        short result = 0;
        result |= ((int)extractByte(offset + 0)) & 255;
        result <<= 8;
        result |= ((int)extractByte(offset + 1)) & 255;
        return result;
      }

      private int extractInt(int offset) {
        int result = 0;
        result |= extractShort(offset + 0) & 65535;
        result <<= 16;
        result |= extractShort(offset + 2) & 65535;
        return result;
      }

      private long extractLong(int offset) {
        long result = 0;
        result |= extractInt(offset + 0) & 4294967295L;
        result <<= 32;
        result |= extractInt(offset + 4) & 4294967295L;
        return result;
      }

      public NSTimestamp timestamp() {
        return new NSTimestamp(milliseconds());
      }
     
      public long milliseconds() {
         return extractLong(_TimestampStartIndex);
      }
     
      public InetAddress host() {
        try {
          byte data[] = new byte[4];
          System.arraycopy(_data, _HostIdentificationStartIndex + 2, data, 0, 4);
        return InetAddress.getByAddress(data);
      } catch (UnknownHostException e) {
        return null;
      }
      }
      
      public long port() {
      return extractInt(_ProcessIdentificationStartIndex);
      }
     
      public short counter() {
        return extractShort(_CounterStartIndex);
      }
     
      public long random() {
        return extractLong(_RandomStartIndex);
      }
     
      @Override
    public String toString() {
        return host().getHostAddress() + ":" + port() + " " + counter() + "@" + timestamp();
      }
    }
   
    /**
     * Groups an array of global IDs by their entity name.
     * @param globalIDs
     */
    public static NSDictionary globalIDsGroupedByEntityName(NSArray globalIDs) {
        return ERXArrayUtilities.arrayGroupedByKeyPath(globalIDs, "entityName");
    }

    /**
     * Translates an array of {@link EOGlobalID} to primary key values. Returns null if the given
     * global IDs are not EOKeyValueGlobalIDs and the primary keys are not single values.
     * @param globalIDs
     */
    public static NSArray<Object> primaryKeyValuesWithGlobalIDs(NSArray<EOGlobalID> globalIDs) {
      NSMutableArray<Object> result = new NSMutableArray<Object>();
      if(globalIDs.count() > 0) {
        NSDictionary gidsByEntity = globalIDsGroupedByEntityName(globalIDs);
        for(Enumeration e = gidsByEntity.keyEnumerator(); e.hasMoreElements();) {
          String entityName = (String) e.nextElement();
          NSArray gidsForEntity = (NSArray) gidsByEntity.objectForKey(entityName);
         
          for (Enumeration gids = gidsForEntity.objectEnumerator(); gids.hasMoreElements();) {
            EOKeyGlobalID keyGID = (EOKeyGlobalID) gids.nextElement();
            if(keyGID.keyCount() == 1) {
              result.addObject(keyGID.keyValues()[0]);
            } else {
              throw new IllegalArgumentException("GID has more than one key: " + keyGID);
            }
          }
        }
      }
      return result;
    }
   
    /**
     * Translates an array of single-value raw primary values to EOGlobalIDs.
     * @param entityName
     * @param values
     */
    public static NSArray<EOGlobalID> globalIDsWithPrimaryKeyValues(String entityName, NSArray<Object> values) {
        NSMutableArray<EOGlobalID> result = new NSMutableArray<EOGlobalID>();
        if(values.count() > 0) {
            for (Enumeration pks = values.objectEnumerator(); pks.hasMoreElements();) {
                Object value = pks.nextElement();
                EOKeyGlobalID gid = EOKeyGlobalID.globalIDWithEntityName(entityName, new Object[] {value});
                result.addObject(gid);
            }
        }
        return result;
    }

    /**
     * Fetches an object defined by gid without refreshing refetched objects.
     *
     * @param ec the editing context to fetch within
     * @param gid the global id to fetch
     * @return the fetched EO
     */
    public static EOEnterpriseObject fetchObjectWithGlobalID(EOEditingContext ec, EOGlobalID gid) {
      NSArray results = ERXEOGlobalIDUtilities.fetchObjectsWithGlobalIDs(ec, new NSArray<EOGlobalID>(gid));
      EOEnterpriseObject eo;
      if (results.count() > 0) {
        eo = (EOEnterpriseObject) results.objectAtIndex(0);
      }
      else {
        eo = null;
      }
      return eo;
    }
   
    /**
     * Fetches an array of objects defined by the globalIDs in a single fetch per entity without
     * refreshing refetched objects.
     *
     * @param ec the editing context to fetch within
     * @param globalIDs the global ids to fetch
     * @return the fetched EO's
     */
    public static NSMutableArray fetchObjectsWithGlobalIDs(EOEditingContext ec, NSArray globalIDs) {
      return ERXEOGlobalIDUtilities.fetchObjectsWithGlobalIDs(ec, globalIDs, false);
    }

    /**
     * Fetches an array of objects defined by the globalIDs in a single fetch per entity.
     *
     * @param ec the editing context to fetch within
     * @param globalIDs the global ids to fetch
     * @param refreshesRefetchedObjects whether or not to refresh refetched objects
     * @return the fetched EO's
     */
    @SuppressWarnings("unchecked")
  public static NSMutableArray fetchObjectsWithGlobalIDs(EOEditingContext ec, NSArray globalIDs, boolean refreshesRefetchedObjects) {
      NSMutableArray<EOEnterpriseObject> result = new NSMutableArray<EOEnterpriseObject>();
    ec.lock();
    ec.rootObjectStore().lock();
    try {
        NSDictionary gidsByEntity = globalIDsGroupedByEntityName(globalIDs);
        for(Enumeration e = gidsByEntity.keyEnumerator(); e.hasMoreElements();) {
          String entityName = (String) e.nextElement();
          NSArray gidsForEntity = (NSArray) gidsByEntity.objectForKey(entityName);
         
          NSMutableArray<EOQualifier> qualifiers = new NSMutableArray<EOQualifier>();
            EOEntity entity = ERXEOAccessUtilities.entityNamed(ec, entityName);
          for (Enumeration gids = gidsForEntity.objectEnumerator(); gids.hasMoreElements();) {
            EOGlobalID g = (EOGlobalID) gids.nextElement();
            boolean fetch = refreshesRefetchedObjects;
            if (!fetch) {
              EOEnterpriseObject eo;
            eo = ec.objectForGlobalID(g);
              if (eo != null && !EOFaultHandler.isFault(eo)) {
                result.addObject(eo);
              }
              else {
                NSDictionary row;
                    EODatabaseContext databaseContext = (EODatabaseContext) ((EOObjectStoreCoordinator) ec.rootObjectStore()).objectStoreForGlobalID(g);
                    databaseContext.lock();
                    try {
                  row = databaseContext.snapshotForGlobalID(g, ec.fetchTimestamp());
                    }
                    finally {
                      databaseContext.unlock();
                    }
                if (row == null) {
                  fetch = true;
                }
                else {
                  eo = ec.faultForGlobalID(g, ec);
                  result.addObject(eo);
                }
              }
            }
            if (fetch) {
              EOQualifier qualifier = entity.qualifierForPrimaryKey(entity.primaryKeyForGlobalID(g));
              qualifiers.addObject(qualifier);
            }
          }
          if (qualifiers.count() > 0) {
            EOQualifier qualifier = qualifiers.count() > 1 ? new EOOrQualifier(qualifiers) : qualifiers.lastObject();
            EOFetchSpecification fetchSpec = new EOFetchSpecification(entityName, qualifier, null);
            fetchSpec.setRefreshesRefetchedObjects(refreshesRefetchedObjects);
            NSArray<EOEnterpriseObject> details = ec.objectsWithFetchSpecification(fetchSpec);
            result.addObjectsFromArray(details);
          }
        }
    }
    finally {
      ec.rootObjectStore().unlock();
      ec.unlock();
    }
      return result;
    }

    /**
     * Fires all faults in the given global IDs on one batch together with their relationships.
     * This is much more efficient than triggering the individual faults and relationships later on.
     * The method should use only 1 fetch for all objects per entity
     * and then one for each relationship per entity.
     * @param ec
     * @param globalIDs
     * @param prefetchingKeypaths
     */
    public static NSArray fireFaultsForGlobalIDs(EOEditingContext ec, NSArray globalIDs, NSArray prefetchingKeypaths) {
      NSMutableArray<EOEnterpriseObject> result = new NSMutableArray<EOEnterpriseObject>(globalIDs.count());
      if(globalIDs.count() > 0) {
        NSMutableArray<EOGlobalID> faults = new NSMutableArray<EOGlobalID>(globalIDs.count());
        for (Enumeration ids = globalIDs.objectEnumerator(); ids.hasMoreElements();) {
          EOGlobalID gid = (EOGlobalID) ids.nextElement();
          EOEnterpriseObject eo = ec.faultForGlobalID(gid, ec);
          if(EOFaultHandler.isFault(eo)) {
            faults.addObject(gid);
          } else {
            result.addObject(eo);
          }
        }
        NSArray<EOEnterpriseObject> loadedObjects = fetchObjectsWithGlobalIDs(ec, faults);
        result.addObjectsFromArray(loadedObjects);
        if(prefetchingKeypaths != null && prefetchingKeypaths.count() > 0) {
          NSDictionary objectsByEntity = ERXArrayUtilities.arrayGroupedByKeyPath(result, "entityName");
          for(Enumeration e = objectsByEntity.keyEnumerator(); e.hasMoreElements();) {
            String entityName = (String) e.nextElement();
            NSArray objects = (NSArray) objectsByEntity.objectForKey(entityName);
            EOEntity entity = ERXEOAccessUtilities.entityNamed(ec, entityName);
            for (Enumeration keyPaths = prefetchingKeypaths.objectEnumerator(); keyPaths.hasMoreElements();) {
              String keypath = (String) keyPaths.nextElement();
              EORelationship relationship = entity.relationshipNamed(keypath);
              EODatabaseContext dbc = ERXEOAccessUtilities.databaseContextForEntityNamed((EOObjectStoreCoordinator) ec.rootObjectStore(), entityName);
              dbc.lock();
              try {
                dbc.batchFetchRelationship(relationship, objects, ec);
              } finally {
                dbc.unlock();
              }
            }
          }
        }
      }
      return result;
    }
   
    /**
     * Fires all faults in the given global IDs on one batch. This is much more efficient than
     * triggering the individual faults later on. The method should use only 1 fetch for all objects per entity.
     * @param ec
     * @param globalIDs
     */
    public static NSArray fireFaultsForGlobalIDs(EOEditingContext ec, NSArray globalIDs) {
        return fireFaultsForGlobalIDs(ec, globalIDs, NSArray.EmptyArray);
    }

  public static EOKeyGlobalID createGlobalID(String entityName, Object[] values) {
    if (values != null && values.length == 1) {
      Object primaryKey = values[0];
      if (primaryKey instanceof Number) {
        return new _EOIntegralKeyGlobalID(entityName, (Number) primaryKey);
      }
    }
    return new _EOVectorKeyGlobalID(entityName, values);
  }
}
TOP

Related Classes of er.extensions.eof.ERXEOGlobalIDUtilities$Info

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.