/* Wotonomy: OpenStep design patterns for pure Java applications. Copyright (C) 2001 Michael Powers This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, see http://www.gnu.org */ package net.wotonomy.access; import net.wotonomy.foundation.NSArray; import net.wotonomy.foundation.NSData; import net.wotonomy.foundation.NSDictionary; import net.wotonomy.foundation.NSKeyValueCoding; import net.wotonomy.foundation.NSMutableArray; import net.wotonomy.foundation.NSMutableDictionary; import net.wotonomy.foundation.NSTimestamp; /** * * @author ezamudio@nasoft.com * @author $Author: cgruber $ * @version $Revision: 894 $ */ public abstract class EOAdaptor { protected String _name; protected NSDictionary _connectionDictionary = NSDictionary.EmptyDictionary; protected NSMutableArray _contexts = new NSMutableArray(); protected Class _expressionClass; private static NSMutableDictionary _expressionClassesByName = new NSMutableDictionary(); public EOAdaptor(String name) { super(); _name = name; } /** * Creates an adaptor with model's adaptorName and sets its connection * dictionary to the model's connection dictionary. * * @param model The model to take adaptorName and connectionDictionary from. * @return The adaptor specified in model. */ public static EOAdaptor adaptorWithModel(EOModel model) { if (model == null) throw new IllegalArgumentException("Model must not be null."); if (model.adaptorName() == null || model.adaptorName().length() == 0) throw new IllegalArgumentException("Cannot create an adaptor with an empty name."); EOAdaptor adaptor = adaptorWithName(model.adaptorName()); if (adaptor == null) throw new IllegalArgumentException("Cannot create adaptor with name " + model.adaptorName()); adaptor.setConnectionDictionary(model.connectionDictionary()); return adaptor; } /** * Instantiates an adaptor of a concrete EOAdaptor subclass, based on name. If * name is a fully qualified class name, then it returns an instance of that * class by invoking the constructor with a string argument. Otherwise, it tries * to find a class called (name)Adaptor in a package called * net.wotonomy.(lowercase name)adaptor; if it can't find one, an exception is * raised. * * @param name The name of the adaptor, or a fully qualified class name. * @return */ public static EOAdaptor adaptorWithName(String name) { Class adaptorClass = null; String cname = null; if (name.endsWith("Adaptor") && name.indexOf('.') > 0) { cname = name; int lastdot = name.lastIndexOf('.'); // take off the package and the 'Adaptor' suffix name = cname.substring(lastdot, cname.length() - 7); } else { // construct the fully qualified class name cname = "net.wotonomy." + name.toLowerCase() + "adaptor." + name + "Adaptor"; } try { adaptorClass = Class.forName(cname); } catch (ClassNotFoundException ex) { throw new IllegalArgumentException("Cannot find class named " + name); } EOAdaptor adaptor = null; java.lang.reflect.Constructor callme = null; try { callme = adaptorClass.getConstructor(new Class[] { String.class }); adaptor = (EOAdaptor) callme.newInstance((Object[]) new String[] { name }); } catch (ClassCastException ex) { throw new IllegalArgumentException( "Class " + adaptorClass.getName() + " must inherit from net.wotonomy.access.EOAdaptor"); } catch (Exception ex) { throw new IllegalArgumentException( "Cannot find or invoke constructor with name argument in class " + adaptorClass.getName()); } return adaptor; } public static void setExpressionClassName(String expClassName, String adaptorClassName) { _expressionClassesByName.setObjectForKey(expClassName, adaptorClassName); } public static String expressionClassName(String adaptorClassName) { return (String) _expressionClassesByName.objectForKey(adaptorClassName); } public void assignExternalInfoForAttribute(EOAttribute attribute) { if (!attribute.isDerived()) { attribute.setColumnName(attribute.name().toUpperCase()); } assignExternalTypeForAttribute(attribute); } public void assignExternalTypeForAttribute(EOAttribute attribute) { } public void assignExternalInfoForEntity(EOEntity entity) { entity.setExternalName(entity.name().toUpperCase()); } public void assignExternalInfoForEntireModel(EOModel model) { NSArray ents = model.entities(); for (int i = 0; i < ents.count(); i++) { EOEntity e = (EOEntity) ents.objectAtIndex(i); // TODO: check that entity is not a prototypes entity NSArray atts = e.attributes(); for (int j = 0; j < atts.count(); j++) { EOAttribute a = (EOAttribute) atts.objectAtIndex(i); assignExternalInfoForAttribute(a); } assignExternalInfoForEntity(e); } } public boolean canServiceModel(EOModel model) { NSDictionary mcd = model.connectionDictionary(); if (mcd == null && _connectionDictionary == null) return true; if (mcd == null || _connectionDictionary == null) return false; return mcd.equals(_connectionDictionary); } public void setConnectionDictionary(NSDictionary connection) { _connectionDictionary = connection; } public NSDictionary connectionDictionary() { return _connectionDictionary; } public NSArray contexts() { return new NSArray(_contexts); } public abstract void assertConnectionDictionaryIsValid(); public abstract EOAdaptorContext createAdaptorContext(); public abstract Class defaultExpressionClass(); public abstract EOSQLExpressionFactory expressionFactory(); public abstract boolean isValidQualifierType(String typeName, EOModel model); public Class expressionClass() { if (_expressionClass != null) return _expressionClass; String cname = expressionClassName(name()); if (cname != null) { try { _expressionClass = Class.forName(cname); } catch (ClassNotFoundException ex) { throw new IllegalStateException("Cannot find expression class named " + cname); } } return defaultExpressionClass(); } public NSArray externalTypesWithModel(EOModel model) { return NSArray.EmptyArray; } public NSData fetchedValueForDataValue(NSData value, EOAttribute attr) { return value; } public NSTimestamp fetchedValueForDateValue(NSTimestamp value, EOAttribute attr) { return value; } public Number fetchedValueForNumberValue(Number value, EOAttribute attr) { return value; } public String fetchedValueForStringValue(String value, EOAttribute attr) { return value; } public Object fetchedValueForValue(Object value, EOAttribute attr) { if (value == NSKeyValueCoding.NullValue) return value; if (value instanceof String) return fetchedValueForStringValue((String) value, attr); if (value instanceof NSData) return fetchedValueForDataValue((NSData) value, attr); if (value instanceof Number) return fetchedValueForNumberValue((Number) value, attr); if (value instanceof NSTimestamp) return fetchedValueForDateValue((NSTimestamp) value, attr); return value; } public void handleDroppedConnection() { for (int i = 0; i < _contexts.count(); i++) { EOAdaptorContext c = (EOAdaptorContext) _contexts.objectAtIndex(i); c.transactionDidRollback(); c.handleDroppedConnection(); } _contexts.removeAllObjects(); } public boolean hasOpenChannels() { for (int i = 0; i < _contexts.count(); i++) { EOAdaptorContext c = (EOAdaptorContext) _contexts.objectAtIndex(i); if (c.hasOpenChannels()) return true; } return false; } public String internalTypeForExternalType(String extType, EOModel model) { return null; } public boolean isDroppedConnectionException(Exception ex) { return false; } public String name() { return _name; } public NSArray prototypeAttributes() { return NSArray.EmptyArray; } } /* * $Log$ Revision 1.2 2006/02/16 16:47:14 cgruber Move some classes in to * "internal" packages and re-work imports, etc. * * Also use UnsupportedOperationExceptions where appropriate, instead of * WotonomyExceptions. * * Revision 1.1 2006/02/16 13:19:57 cgruber Check in all sources in * eclipse-friendly maven-enabled packages. * * Revision 1.2 2005/12/08 06:52:32 cgruber Move tests, improve build.xml, and * make certain casts explicit so that Java 1.5 doesn't complain about varargs. * * Revision 1.1 2003/08/13 00:37:45 chochos an almost complete implementation of * the abstract adaptor-layer classes * */