Below is our Oracle extension of EROraclePlugIn and ERXJDBCAdaptor. I overrode 
method JDBCAdaptor.newPrimaryKeys() to cache primary keys and reduce database 
roundtrips to get the sequence’s NEXTVAL. The code also contains some other 
Oracle specific features like storing the pid and app name in Oracle’s 
v$session…

I would like to add code to determine the sequence INCREMENT_BY value rather 
than depending on the developer and or DBA to update the Oracle sequence value 
and Entity.userInfo dictionary (ERXPrimaryKeyBatchSize #).

Does any one have an example of executing a select from ERXJDBCAdaptor (SELECT 
INCREMENT_BY FROM ALL_SEQUENCES WHERE SEQUENCE_NAME = '<TABLE_NAME>_SEQ';)?

public class MYOraclePlugIn extends EROraclePlugIn {

        public MYOraclePlugIn(JDBCAdaptor adaptor) {
                super(adaptor);
        }
        
        protected Class<?> defaultExpressionClass;
        
        /* (non-Javadoc)
         * @see com.webobjects.jdbcadaptor.JDBCPlugIn#defaultExpressionClass()
         */
        public Class<?> defaultExpressionClass() {
                if (defaultExpressionClass == null) {
                        if (MYOracleExpression.isFetchLimitSupportEnabled()) {
                                defaultExpressionClass = 
MYOracleExpression.class;                              
                        } else {
                                defaultExpressionClass = OracleExpression.class;
                        }
                }
                
                return defaultExpressionClass;
        }

        /**
         * Overriden to augment the connection properties to enable the DBA to 
see the application name 
         * and PID for WO5 apps.
         */
        @Override
        public Properties 
connectionPropertiesForConnectionDictionary(@SuppressWarnings("rawtypes") 
NSDictionary nsdictionary) {
                Properties properties = 
super.connectionPropertiesForConnectionDictionary(nsdictionary);

                // Oracle specific properties
                if (properties != null) {
                        String pid = "" + System_Additions.processID();
                        String processName = System_Additions.processName();
                        Number port = System_Additions.port();
                        String host = System_Additions.hostName();
                        
                        String program = processName + ":" + port + "@" + host;
                        
                        if (program.length() > 41) {
                                program = StringUtils.truncate(program, 41, "");
                        }
                        
                        if (null != processName) {
                                properties.put("v$session.program", program);
                        }

                        if (null != pid) {
                                properties.put("v$session.process", pid);
                        }
                        
                        Boolean isBackgroundTask = (Boolean) 
ERXThreadStorage.valueForKey(MYTask.IS_BACKGROUND_TASK_KEY);
                        if (isBackgroundTask != null) {
                                properties.put("v$session.program", program + 
"-job");
                        }
            }

                return properties;
        }
        
        /**
         * The whole purpose of this MYJDBCAdaptorPatch class is to expose 
         * the JDBCAdaptor's _cachedContext protected i-var.  This allows the
         * plugin's jdbcInfo() method to access this cached context object
         * and close it after using it to fetch the JDBC info.
         */
        public static class MYJDBCAdaptorPatch extends ERXJDBCAdaptor {

                public MYJDBCAdaptorPatch(String name) {
                        super(name);
                }
                
                public JDBCContext cachedAdaptorContext() {
                        return (JDBCContext) this.createAdaptorContext();
                }
        }

        /** 
         * Overrides method jdbcInfo() in order to close the database connection
         * used to fetch the JDBC info.
         */
        @Override
        public NSDictionary<String, Object> jdbcInfo() {
                NSDictionary<String, Object> jdbcInfo;
                
                // Just in case two different adaptors share the same plug-in 
and this
                // method happens to get called by different threads it seems 
like a
                // good idea to guard this code that swaps out the _adaptor 
i-var
                // so that the _adaptor is not restored by the other thread 
while in
                // the middle of doing this.
                
                synchronized(this) {
                        // Remember the current adaptor
                        JDBCAdaptor adaptor = _adaptor;
                        
                        // Instantiate and setup our adaptor patch that gives 
us access to  
                        // the object used to fetch the JDBC info. 
                        MYJDBCAdaptorPatch newAdaptor = new 
MYJDBCAdaptorPatch("JDBC");
                        
newAdaptor.setConnectionDictionary(adaptor.connectionDictionary());
                        
                        // Now swap out this plugin's adaptor with ours 
temporarily so that 
                        // when we call jdbcInfo() in the JDBCPlugIn superclass 
it ends up
                        // getting the secondary JDBC context in it to fetch 
the JDBC info.
                        // And because our adaptor exposes this secondary JDBC 
context object
                        // we can disconnect it from the database here.  Then 
we restore the
                        // adaptor in use before the swap.
                        
                        _adaptor = newAdaptor;  // swap
                        jdbcInfo = super.jdbcInfo();
                        newAdaptor.cachedAdaptorContext().disconnect();
                        _adaptor = adaptor;             // restore
                }
                
                return jdbcInfo;
        }

        @SuppressWarnings("rawtypes")
        private static NSMutableDictionary<String, NSMutableArray> pkCache = 
new NSMutableDictionary<String, NSMutableArray>();
        private int defaultBatchSize = 
ERXProperties.intForKeyWithDefault("er.extensions.ERXPrimaryKeyBatchSize", -1);
        
        /**
         * Return an array of dictionaries with primary keys for 
<code>entity</code>.
         * Set er.extensions.ERXPrimaryKeyBatchSize to 1 and add Entity 
userInfo dictionary ERXPrimaryKeyBatchSize <Oracle INCREMENT_BY for sequence>
         * SELECT INCREMENT_BY FROM ALL_SEQUENCES WHERE SEQUENCE_NAME = 
'<TABLE_NAME>_SEQ';
         */
        @Override
        public NSArray<NSDictionary<String, Object>> newPrimaryKeys(int count, 
EOEntity entity, JDBCChannel channel) {
        
                Object batchSize = (entity.userInfo() != null ? 
entity.userInfo().objectForKey("ERXPrimaryKeyBatchSize") : null);
                
                if (defaultBatchSize > 0 && null != batchSize) {
                        
                        synchronized (pkCache) {
                                
                                String key = entity.primaryKeyRootName();
                                @SuppressWarnings("unchecked")
                                NSMutableArray<NSMutableDictionary<String, 
Object>> pks = pkCache.objectForKey(key);
                                
                                if (pks == null) {
                                        pks = new 
NSMutableArray<NSMutableDictionary<String, Object>>();
                                        pkCache.setObjectForKey(pks, key);
                                }
                                
                                if (pks.count() < count) {
                                        
                                        int size = 
ERXValueUtilities.intValue(batchSize);
                                        
                                        
pks.addObjectsFromArray(_newPrimaryKeys(size + count, entity, channel, size));
                                }
                                
                                NSMutableArray<NSDictionary<String, Object>> 
batch = new NSMutableArray<NSDictionary<String, Object>>();
                                
                                for (Iterator<NSMutableDictionary<String, 
Object>> iterator = pks.iterator(); iterator.hasNext() && --count >= 0;) {
                                        NSMutableDictionary<String, Object> pk 
= iterator.next();
                                        batch.addObject(pk);
                                        iterator.remove();
                                }
                                
                                return batch;
                        }
                }
                
                return super.newPrimaryKeys(count, entity, channel);
        }
        
        private NSArray<NSMutableDictionary<String, Object>> 
_newPrimaryKeys(int count, EOEntity entity, JDBCChannel channel, int batchSize) 
{
                
                NSMutableArray<NSMutableDictionary<String, Object>> pks = new 
NSMutableArray<NSMutableDictionary<String, Object>>(count);
                int iMax = (int) Math.ceil((double)count / batchSize);
                NSArray<NSDictionary<String, Object>> npks = 
super.newPrimaryKeys(iMax, entity, channel);
                
                for (NSDictionary<String, Object> pk : npks) {
                        pks.addObjectsFromArray(incrementPrimaryKey(pk, 
batchSize));
                }
                
                return pks;
        }
        
        private NSArray<? extends NSMutableDictionary<String, Object>> 
incrementPrimaryKey(NSDictionary<String, Object> pk, int batchSize) {
                
                NSMutableArray<NSMutableDictionary<String, Object>> pks = new 
NSMutableArray<NSMutableDictionary<String, Object>>(batchSize);
                
                pks.addObject((NSMutableDictionary<String, Object>) pk);
                
                for (int i = 1, iMax = batchSize; i < iMax; i++) {
                        @SuppressWarnings("unchecked")
                        NSMutableDictionary<String, Object> pkClone = 
(NSMutableDictionary<String, Object>) pk.clone();
                        
                        for (String key : pkClone.keySet()) {
                                Object value = pkClone.get(key);
                                
                                if (value instanceof Number) {
                                        long newVal = ((Number) 
value).longValue() + i;
                                        pkClone.takeValueForKey(new 
Long(newVal), key);
                                        pks.addObject(pkClone);
                                }
                        }
                }
                
                return pks;
        }
}


 _______________________________________________
Do not post admin requests to the list. They will be ignored.
Webobjects-dev mailing list      ([email protected])
Help/Unsubscribe/Update your Subscription:
https://lists.apple.com/mailman/options/webobjects-dev/archive%40mail-archive.com

This email sent to [email protected]

Reply via email to