View Javadoc

1   /* (c) Copyright 2003 Caleigo AB, All rights reserved. 
2    * 
3    * This library is free software; you can redistribute it and/or
4    * modify it under the terms of the GNU Lesser General Public
5    * License as published by the Free Software Foundation; either
6    * version 2.1 of the License, or (at your option) any later version.
7    * 
8    * This library is distributed in the hope that it will be useful,
9    * but WITHOUT ANY WARRANTY; without even the implied warranty of
10   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11   * Lesser General Public License for more details.
12   * 
13   * You should have received a copy of the GNU Lesser General Public
14   * License along with this library; if not, write to the Free Software
15   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16   *  
17   */
18  
19  package org.caleigo.core;
20  
21  import org.caleigo.core.event.*;
22  import org.caleigo.core.exception.*;
23  import org.caleigo.toolkit.log.*;
24  
25  
26  /*** <Description for ControledProxyEntity>
27   *
28   * @author  Dennis Zikovic
29   * @version 1.00
30   *
31   *//* 
32   *
33   * WHEN        WHO               WHY & WHAT
34   * -----------------------------------------------------------------------------
35   * 2002-04-30  Dennis Zikovic    Creation
36   */
37  public class ControlledProxyEntity extends ProxyEntity implements IControlledProxy
38  {
39      // Constants ---------------------------------------------------------------
40      
41      // Data members ------------------------------------------------------------
42      private IProxyController mControlEntityProxy;
43      private IEntityRelationPath mRelationPath;
44      
45      private Qualifier mRelationQualifier;
46      private IFieldDescriptor[] mReferenceFields;
47      private IFieldDescriptor[] mTargetFields;
48      
49      private IEntity mLoadEntity;
50      
51      // Constructors ------------------------------------------------------------
52      
53      /*** Creates new ControledSelectionProxy. Note protected scope the class 
54       * should normally be instantiated by a call to object impementing the
55       * IProxyController interface and the getControlledProxy method.
56       */
57      protected ControlledProxyEntity(IProxyController controller, IEntityDescriptor entityDescriptor) 
58      {
59          this(controller, entityDescriptor, null);
60      }
61      
62      /*** Creates new ControledSelectionProxy. Note protected scope the class 
63       * should normally be instantiated by a call to object impementing the
64       * IProxyController interface and the getControlledProxy method.
65       */
66      protected ControlledProxyEntity(IProxyController controller, IEntityDescriptor entityDescriptor, IEntityRelationPath relationPath) 
67      {
68          super(entityDescriptor);
69          
70          // Verify the relation path.
71          if(relationPath!=null && !relationPath.isRelatedByPath(controller.getEntityDescriptor(), entityDescriptor))
72              throw new InvalidRelationException("The relation path is not valid for the descriptors "+controller.getEntityDescriptor()+" and "+entityDescriptor);
73          
74          // Store controller and relation path.
75          mControlEntityProxy = controller;
76          if(relationPath!=null)
77              mRelationPath = relationPath;
78          else
79              mRelationPath = this.createRelationPath();
80          
81          // Make evaluation field array.
82          mReferenceFields = new IFieldDescriptor[mRelationPath.getRelation(0).getFieldCount()];
83          mTargetFields = new IFieldDescriptor[mRelationPath.getRelation(0).getFieldCount()];
84          for(int j=0; j<mRelationPath.getRelation(0).getFieldCount(); j++)
85          {
86              mReferenceFields[j] = mRelationPath.getRelation(0).getFieldRelation(j).getReferenceField();
87              mTargetFields[j] = mRelationPath.getRelation(0).getFieldRelation(j).getTargetField();
88          }
89          if(mRelationPath.getRelationCount()>1)
90          {
91              IEntityRelationPath subPath = Relations.getSubRelationPath(mRelationPath, 1);
92              mRelationQualifier = subPath.getRelationQualifier();
93          }
94          else
95              mRelationQualifier = null;
96          
97          // Register new control listeners.
98          ControllListener listener = new ControllListener();
99          mControlEntityProxy.addProxyListener(listener);
100         mControlEntityProxy.addEntityChangeListener(listener);
101                 
102         // Load data.
103         this.loadControlledProxies(true);
104     }
105     
106     // Superclass overrides ----------------------------------------------------
107     protected void loadControlledProxies(boolean includeLocalRemote) throws DataServiceException
108     {
109         IDataTransaction transaction = this.getDataSource().getDataService().newTransaction();
110         if(includeLocalRemote)
111             this.prepareLoad(transaction);
112         else if(this.getSourceEntity()==null)
113             return;
114         
115         // Prepare transaction with controlled proxies actions.
116         try
117         {
118             AsyncTransactionHandler transactionHandler = AsyncTransactionHandler.create();
119             transactionHandler.setCallback(this, "loadControlledProxiesCallback");
120             if(!transaction.isEmpty())
121                 transactionHandler.commit(transaction);
122             else
123             {
124                 this.finalizeTransaction(true);
125                 this.updateDirtyState();
126             }
127             
128 //            this.prepareControlledLoad(transaction);
129 //            if(!transaction.isEmpty())
130 //                transaction.commit();
131 //            this.finalizeTransaction(true);
132 //            this.updateDirtyState();
133         }
134         catch(DataServiceException e)
135         {
136             this.finalizeTransaction(false);
137             Log.printError(this, "Store transaction failed in proxy controller "+this);
138             throw e;
139         }
140         
141         this.updateDirtyState();
142     }
143 
144     public void loadControlledProxiesCallback(int status)
145     {
146         if (status == AsyncTransactionHandler.COMMIT_SUCCEEDED)
147             this.finalizeTransaction(true);
148         else
149             this.finalizeTransaction(false);
150             
151         this.updateDirtyState();
152     }
153     
154     // IControlledProxy implementation -----------------------------------------
155     
156     public IProxyController getController()
157     {
158         return mControlEntityProxy; 
159     }
160     
161     public IEntityRelationPath getRelationPath()
162     {
163         return mRelationPath;
164     }
165 
166     public boolean isEditable()
167     {
168         return true;
169     }
170     
171     public void prepareLoad(IDataTransaction transaction)
172     {
173         if(mControlEntityProxy==null || mControlEntityProxy.isEmpty())
174             this.setRemoteEntity(null);
175         else
176         {
177             Qualifier qual = null;
178             if(mTargetFields!=null)
179             {
180                 for(int j=0; j<mTargetFields.length; j++)
181                     qual = Qualifier.combine(qual, new RelationQualifier(mTargetFields[j], mControlEntityProxy.getData(mReferenceFields[0])));
182                 if(mRelationQualifier!=null)
183                     qual = qual.and(mRelationQualifier);
184             }
185             else
186                 qual = mControlEntityProxy.getOriginQualifier().and(mRelationPath.getRelationQualifier());
187             
188             mLoadEntity = this.getEntityDescriptor().createEntity();
189             transaction.addLoad(qual, mLoadEntity);
190         }
191         
192         // Call superclass to recurse to child proxies.
193         this.prepareControlledLoad(transaction);
194     }
195 
196     public void prepareStore(IDataTransaction transaction)
197     {
198         if(this.hasRemoteEntity() && this.getRemoteEntity().isDirty())
199         {
200             ITransactionEntityAction action = (ITransactionEntityAction)this.getEntityDescriptor().getAction(IEntityDescriptor.STORE_ACTION);
201             IDataBundle data = action.getDataBundleDescriptor().createActionData();
202             data.setData(0, this.getSourceEntity());
203             action.prepareTransaction(data, transaction);
204         }
205         
206         // Call superclass to recurse to child proxies.
207         this.prepareControlledStore(transaction);
208     }
209     
210     /*** The finalizeTransaction method is called after a transaction have been
211      * fully completed. This method will always be called once after any call
212      * to prepareLoad or prepareStore.
213      */
214     public void finalizeTransaction(boolean successful)
215     {
216         super.finalizeTransaction(successful);
217         if(successful)
218             this.setRemoteEntity(mLoadEntity);
219 //        mLoadEntity = null;
220     }
221      
222     // Help methods ------------------------------------------------------------
223     
224 //    protected void loadRemoteEntity()
225 //    {
226 //        IDataTransaction transaction = this.getEntityDescriptor().getDataSourceDescriptor().getDefaultDataSource().getDataService().newTransaction();
227 //        this.prepareLoad(transaction);
228 //        transaction.commit();
229 //    }
230 
231     /*** This method is called each time the view entity object are replaced.
232      * It is called prior to doOnControllerDataChange and cand does nothing 
233      * by default.
234      */
235     protected void doOnControllerChange()
236     {
237     }
238     
239     /*** This method is called each time any data in the viewed entity data are 
240      * changed. It is called emidiately after doOnControllerChange and calls 
241      * refreshRemoteSelection if any reference fields are changed.
242      */
243     protected void doOnControllerDataChange(IFieldDescriptor fieldDescriptor)
244     {
245         if(mReferenceFields!=null && fieldDescriptor!=null)
246             for(int j=0; j<mReferenceFields.length; j++)
247                 if(mReferenceFields[j]==fieldDescriptor)
248                 {
249                      this.loadControlledProxies(true);
250                      return;
251                 }
252     }
253     
254     /*** Protected help method responsible for  creating the relation path 
255      * between the master and slave descriptor. The method is only called 
256      * if no relation path was provided in the object construction. By default
257      * i creates a new EntityRelationPath with no provided waypoint by  it can
258      * be overrriden for more customized bahaviour.
259      */
260     protected IEntityRelationPath createRelationPath()
261     {
262         return EntityRelationPath.create(mControlEntityProxy.getEntityDescriptor(), this.getEntityDescriptor());
263     }
264     
265     // Nested classes ----------------------------------------------------------
266     
267     protected class ControllListener implements IEntityChangeListener, IProxyListener
268     {
269         // IEntityChangeListener implemntation ---------------------------------
270         public void dataChanged(EntityChangeEvent event)
271         {
272             doOnControllerDataChange(event.getFieldDescriptor());
273         }
274 
275         public void statusChanged(EntityChangeEvent event)
276         {
277         }
278         
279         // IProxyListener implementation ---------------------------------------
280         public void remoteChanged(ProxyEvent event)
281         {
282             doOnControllerChange();
283             doOnControllerDataChange(null);
284         }
285 
286         public void remoteExpanded(ProxyEvent event)
287         {
288             doOnControllerDataChange(null);
289         }
290     }
291 }