001: //$Id: PropertyAccessorFactory.java 8451 2005-10-24 08:45:37Z maxcsaucdk $
002: package org.hibernate.property;
003:
004: import java.util.Map;
005:
006: import org.hibernate.MappingException;
007: import org.hibernate.EntityMode;
008: import org.hibernate.type.Type;
009: import org.hibernate.engine.SessionFactoryImplementor;
010: import org.hibernate.mapping.Property;
011: import org.hibernate.util.ReflectHelper;
012: import org.hibernate.util.StringHelper;
013:
014: /**
015: * A factory for building/retrieving PropertyAccessor instances.
016: *
017: * @author Gavin King
018: * @author Steve Ebersole
019: */
020: public final class PropertyAccessorFactory {
021:
022: private static final PropertyAccessor BASIC_PROPERTY_ACCESSOR = new BasicPropertyAccessor();
023: private static final PropertyAccessor DIRECT_PROPERTY_ACCESSOR = new DirectPropertyAccessor();
024: private static final PropertyAccessor MAP_ACCESSOR = new MapAccessor();
025: private static final PropertyAccessor NOOP_ACCESSOR = new NoopAccessor();
026: private static final PropertyAccessor EMBEDDED_PROPERTY_ACCESSOR = new EmbeddedPropertyAccessor();
027:
028: //TODO: ideally we need the construction of PropertyAccessor to take the following:
029: // 1) EntityMode
030: // 2) EntityMode-specific data (i.e., the classname for pojo entities)
031: // 3) Property-specific data based on the EntityMode (i.e., property-name or dom4j-node-name)
032: // The easiest way, with the introduction of the new runtime-metamodel classes, would be the
033: // the following predicates:
034: // 1) PropertyAccessorFactory.getPropertyAccessor() takes references to both a
035: // org.hibernate.metadata.EntityModeMetadata and org.hibernate.metadata.Property
036: // 2) What is now termed a "PropertyAccessor" stores any values needed from those two
037: // pieces of information
038: // 3) Code can then simply call PropertyAccess.getGetter() with no parameters; likewise with
039: // PropertyAccessor.getSetter()
040:
041: /**
042: * Retrieves a PropertyAccessor instance based on the given property definition and
043: * entity mode.
044: *
045: * @param property The property for which to retrieve an accessor.
046: * @param mode The mode for the resulting entity.
047: * @return An appropriate accessor.
048: * @throws MappingException
049: */
050: public static PropertyAccessor getPropertyAccessor(
051: Property property, EntityMode mode) throws MappingException {
052: //TODO: this is temporary in that the end result will probably not take a Property reference per-se.
053: if (null == mode || EntityMode.POJO.equals(mode)) {
054: return getPojoPropertyAccessor(property
055: .getPropertyAccessorName());
056: } else if (EntityMode.MAP.equals(mode)) {
057: return getDynamicMapPropertyAccessor();
058: } else if (EntityMode.DOM4J.equals(mode)) {
059: //TODO: passing null here, because this method is not really used for DOM4J at the moment
060: // but it is still a bug, if we don't get rid of this!
061: return getDom4jPropertyAccessor(property
062: .getAccessorPropertyName(mode), property.getType(),
063: null);
064: } else {
065: throw new MappingException("Unknown entity mode [" + mode
066: + "]");
067: }
068: }
069:
070: /**
071: * Retreives a PropertyAccessor specific for a PojoRepresentation with the given access strategy.
072: *
073: * @param pojoAccessorStrategy The access strategy.
074: * @return An appropriate accessor.
075: */
076: private static PropertyAccessor getPojoPropertyAccessor(
077: String pojoAccessorStrategy) {
078: if (StringHelper.isEmpty(pojoAccessorStrategy)
079: || "property".equals(pojoAccessorStrategy)) {
080: return BASIC_PROPERTY_ACCESSOR;
081: } else if ("field".equals(pojoAccessorStrategy)) {
082: return DIRECT_PROPERTY_ACCESSOR;
083: } else if ("embedded".equals(pojoAccessorStrategy)) {
084: return EMBEDDED_PROPERTY_ACCESSOR;
085: } else if ("noop".equals(pojoAccessorStrategy)) {
086: return NOOP_ACCESSOR;
087: } else {
088: return resolveCustomAccessor(pojoAccessorStrategy);
089: }
090: }
091:
092: public static PropertyAccessor getDynamicMapPropertyAccessor()
093: throws MappingException {
094: return MAP_ACCESSOR;
095: }
096:
097: public static PropertyAccessor getDom4jPropertyAccessor(
098: String nodeName, Type type,
099: SessionFactoryImplementor factory) throws MappingException {
100: //TODO: need some caching scheme? really comes down to decision
101: // regarding amount of state (if any) kept on PropertyAccessors
102: return new Dom4jAccessor(nodeName, type, factory);
103: }
104:
105: private static PropertyAccessor resolveCustomAccessor(
106: String accessorName) {
107: Class accessorClass;
108: try {
109: accessorClass = ReflectHelper.classForName(accessorName);
110: } catch (ClassNotFoundException cnfe) {
111: throw new MappingException(
112: "could not find PropertyAccessor class: "
113: + accessorName, cnfe);
114: }
115: try {
116: return (PropertyAccessor) accessorClass.newInstance();
117: } catch (Exception e) {
118: throw new MappingException(
119: "could not instantiate PropertyAccessor class: "
120: + accessorName, e);
121: }
122: }
123:
124: private PropertyAccessorFactory() {
125: }
126:
127: // todo : this eventually needs to be removed
128: public static PropertyAccessor getPropertyAccessor(
129: Class optionalClass, String type) throws MappingException {
130: if (type == null)
131: type = optionalClass == null || optionalClass == Map.class ? "map"
132: : "property";
133: return getPropertyAccessor(type);
134: }
135:
136: // todo : this eventually needs to be removed
137: public static PropertyAccessor getPropertyAccessor(String type)
138: throws MappingException {
139: if (type == null || "property".equals(type))
140: return BASIC_PROPERTY_ACCESSOR;
141: if ("field".equals(type))
142: return DIRECT_PROPERTY_ACCESSOR;
143: if ("map".equals(type))
144: return MAP_ACCESSOR;
145: if ("embedded".equals(type))
146: return EMBEDDED_PROPERTY_ACCESSOR;
147: if ("noop".equals(type))
148: return NOOP_ACCESSOR;
149:
150: return resolveCustomAccessor(type);
151: }
152: }
|