001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: * $Header:$
018: */
019: package org.apache.beehive.controls.system.ejb;
020:
021: import java.io.Serializable;
022: import java.lang.reflect.InvocationTargetException;
023: import java.lang.reflect.Method;
024: import java.rmi.RemoteException;
025: import java.util.Collection;
026: import java.util.Iterator;
027: import javax.ejb.EJBLocalObject;
028: import javax.ejb.EJBObject;
029:
030: import org.apache.beehive.controls.api.ControlException;
031: import org.apache.beehive.controls.api.bean.ControlImplementation;
032:
033: /**
034: * The EntityEJBControlImpl class is the control implementation class for
035: * Entity EJBs.
036: */
037: @ControlImplementation(assembler=EJBControlAssembler.class)
038: public class EntityEJBControlImpl extends EJBControlImpl implements
039: EntityEJBControl, java.io.Serializable {
040:
041: static final long serialVersionUID = 1L;
042:
043: //
044: // Implements auto-find semantics for entity beans
045: //
046: protected Object resolveBeanInstance() {
047: // Already resolved and cached
048: if (_beanInstance != null)
049: return _beanInstance;
050:
051: // Attempt to resolve from a cached handle
052: _beanInstance = resolveBeanInstanceFromHandle();
053: if (_beanInstance != null)
054: return _beanInstance;
055:
056: // Attempt to resolve bean instance from cached primary key
057: if (_lastKey == null)
058: throw new ControlException(
059: "Unable to locate a target bean instance, because a successful create or finder method has not been executed.");
060:
061: Class[] findArgType = new Class[] { _lastKey.getClass() };
062: try {
063: Method finder = _homeInterface.getMethod(
064: "findByPrimaryKey", findArgType);
065: return finder.invoke(_homeInstance,
066: new Object[] { _lastKey });
067: } catch (NoSuchMethodException nsme) {
068: throw new ControlException(
069: "Unable to locate findByPrimaryKey method on home interface",
070: nsme);
071: } catch (InvocationTargetException ite) {
072: _lastException = ite.getTargetException();
073: throw new ControlException(
074: "Failure to locate entity instance associated with the last primary key",
075: _lastException);
076: } catch (Exception e) {
077: throw new ControlException(
078: "Unexpected exception in auto-find", e);
079: }
080: }
081:
082: protected boolean saveBeanInstance() {
083: //
084: // First, delegate to parent (handle-based persistence)
085: //
086: if (super .saveBeanInstance())
087: return true;
088:
089: //
090: // Fall back to persistence using a saved primary key value
091: //
092: try {
093: if (_beanInstance instanceof EJBObject)
094: _lastKey = (Serializable) ((EJBObject) _beanInstance)
095: .getPrimaryKey();
096: else
097: _lastKey = (Serializable) ((EJBLocalObject) _beanInstance)
098: .getPrimaryKey();
099: } catch (RemoteException re) {
100: throw new ControlException("Unable to save bean instance",
101: re);
102: }
103: return true;
104: }
105:
106: //
107: // Release the bean instance. Entity bean instances are *never* removed, except via
108: // direct client calls to the remove method.
109: //
110: protected void releaseBeanInstance(boolean alreadyRemoved) {
111: super .releaseBeanInstance(alreadyRemoved);
112:
113: // Release any cached primary key value
114: _lastKey = null;
115: }
116:
117: private boolean isMultiSelectorMethod(Method m) {
118: return isFinderMethod(m)
119: && m.getReturnType().isAssignableFrom(Collection.class);
120: }
121:
122: //
123: // This method wraps the base EJBControlImpl invoke, doing the additional
124: // work to maintain the primary key cache for methods which alter the
125: // target bean instance.
126: //
127: public Object invoke(Method m, Object[] args) throws Throwable {
128: Throwable invokeException = null;
129: Object retval = null;
130: Object currentBeanInstance = _beanInstance;
131: try {
132: retval = super .invoke(m, args);
133: } catch (Exception t) {
134: // a tasty treat, but I'll throw up later
135: invokeException = t;
136: }
137:
138: if (isControlBeanMethod(m)) {
139: m = mapControlBeanMethodToEJB(m);
140: }
141:
142: if (isMultiSelectorMethod(m)) {
143: releaseBeanInstance(false);
144:
145: Collection collection = (Collection) retval;
146: if (collection != null && !collection.isEmpty()) {
147: _colIter = collection.iterator();
148: _beanInstance = beanNarrow(_colIter.next());
149: } else
150: releaseBeanInstance(false);
151: } else if (isSelectorMethod(m)) {
152: // Release collection results if a single select method is called.
153: _colIter = null;
154: }
155:
156: if (invokeException != null)
157: throw invokeException;
158:
159: return retval;
160: }
161:
162: /**
163: * EntityEJBControl.getEJBNextBeanInstance()
164: */
165: public Object getEJBNextBeanInstance() {
166: if (_colIter == null)
167: return null;
168:
169: if (!_colIter.hasNext()) {
170: releaseBeanInstance(false);
171: return null;
172: }
173:
174: _beanInstance = beanNarrow(_colIter.next());
175: return _beanInstance;
176: }
177:
178: //
179: // Override the onCreate event handler that was already defined in EJBControlImpl to
180: // add additional processing.
181: //
182: public void onCreate() {
183: super .onCreate();
184: if (_beanType != EJBControlImpl.ENTITY_BEAN) {
185: throw new ControlException(
186: "Attempting to use a entity bean control with a bean that is not a entity bean");
187: }
188: }
189:
190: //
191: // Override the onReset event handler that was already defined in EJBControlImpl to
192: // add additional processing.
193: //
194: public void onReset() {
195: super .onReset();
196: _lastKey = null;
197: _colIter = null;
198: }
199:
200: private Serializable _lastKey; // primary key of the selected instance
201: private transient Iterator _colIter; // multi-finder result iterator
202: }
|