Merging code from trunk that fixes #774, this work was done by incastrix
[phpeclipse.git] / archive / net.sourceforge.phpeclipse.quantum.sql / src / com / quantum / extensions / ProcessServiceMembers.java
1
2 /*
3  * Created on 16-feb-2004
4  *
5  */
6 package com.quantum.extensions;
7 import java.util.Vector;
8
9 import org.eclipse.core.runtime.CoreException;
10 import org.eclipse.core.runtime.IConfigurationElement;
11 import org.eclipse.core.runtime.IExtension;
12 import org.eclipse.core.runtime.IExtensionPoint;
13 import org.eclipse.core.runtime.IPluginRegistry;
14 import org.eclipse.core.runtime.Platform;
15 import org.eclipse.ui.IViewPart;
16 import org.eclipse.ui.WorkbenchException;
17 import org.w3c.dom.Document;
18
19 import com.quantum.view.bookmark.BookmarkView;
20 import com.quantum.view.tableview.TableView;
21
22 /**
23  * Extension processing logic for the <code>functions</code> extension-point.
24  * Extract specific information about each function. Create callback
25  * function object when required.
26  * 
27  * @author panic
28  *
29  */
30 public class ProcessServiceMembers {
31
32         /**
33          * The fully-qualified name of the functions extension-point for this plug-in.
34          */
35         private static final String EXTENSION_POINT_METADATA =
36                 "net.sourceforge.phpeclipse.quantum.sql.metadata";
37         private static final String EXTENSION_POINT_DATA =
38                 "net.sourceforge.phpeclipse.quantum.sql.data";
39
40         /**
41          * Name of the XML attribute designating a metadata actor label.
42          */
43         private static final String FUNCTION_NAME_ATTRIBUTE = "label";
44
45         /**
46          * Name of the XML attribute designating the fully-qualified name 
47          * of the implementation class of a function.
48          */
49         private static final String CLASS_ATTRIBUTE = "class";
50
51         /**
52          * Perform initial extension processing for the members of the
53          * <code>functions</code> extension-point. Make calls to the user interface
54          * module to add the functions of an extension to the UI functions grid.
55          * For each function, a virtual proxy callback object is created and handed
56          * to the user interface module. The proxy class is a nested top-level 
57          * class and is therefore known at compile time. The actual (real) callback
58          * objects configured into extensions are instantiated and initialized in 
59          * a lazy fashion by the proxy callback objects.
60          * 
61          * @param grid The UI functions grid exposing the functions configured
62          *              into <code>functions</code> extensions.
63          * 
64          */
65         public static void process(IViewPart view, Vector extensionActions) throws WorkbenchException {
66                 
67                 extensionActions.clear();
68                 
69                 IPluginRegistry registry = Platform.getPluginRegistry();
70                 String extPointId; 
71                 // We have two different extension points, we choose the needed one based
72                 // on the view that calls this function. 
73                 // Our two extension points have the same attributes, so the only change is the name
74                 // If the implementation differed more, we should probably make two different functions
75                 if (view instanceof BookmarkView)
76                         extPointId = EXTENSION_POINT_METADATA;
77                 else if (view instanceof TableView)
78                         extPointId = EXTENSION_POINT_DATA;
79                 else
80                         return;
81                 
82                 IExtensionPoint extensionPoint =
83                         registry.getExtensionPoint(extPointId);
84                 if (extensionPoint == null) {
85                         throw new WorkbenchException(
86                                 "unable to resolve extension-point: " + extPointId);
87                 }
88                 IConfigurationElement[] members =
89                         extensionPoint.getConfigurationElements();
90
91                 // For each service:
92                 for (int m = 0; m < members.length; m++) {
93                         IConfigurationElement member = members[m];
94                         // Get the label of the extender plugin and the ID of the extension.
95                         IExtension extension = member.getDeclaringExtension();
96                         String pluginLabel =
97                                 extension.getDeclaringPluginDescriptor().getLabel();
98                         if (pluginLabel == null) {
99                                 pluginLabel = "[unnamed plugin]";
100                         }
101                         // Get the name of the operation implemented by the service.
102                         // The operation name is a service attribute in the extension's XML specification.
103                         String functionName = member.getAttribute(FUNCTION_NAME_ATTRIBUTE);
104                         if (functionName == null) {
105                                 functionName = "[unnamed function]";
106                         }
107                         String label = pluginLabel + "/" + functionName;
108                         // Add a row to support this operation to the UI grid.
109                         IQuantumExtension proxy = null;
110                         if (view instanceof BookmarkView)
111                                 proxy = (IMetadataExtension) new MetadataFunctionProxy(member);
112                         else if (view instanceof TableView)
113                                 proxy = (IDataExtension) new DataFunctionProxy(member);
114                         //grid.addFunction(proxy, functionName, label);
115                         extensionActions.add(new ExtensionAction(view, label, label, proxy));
116                 }
117         }
118
119         /**
120          * Virtual proxy class for function invokation.
121          * Members of this class support lazy processing by fronting the real 
122          * implementations of arithmetic functions configured into extensions.
123          */
124         private static class MetadataFunctionProxy implements IMetadataExtension {
125                 // The "real" implementation of the function.
126                 private IMetadataExtension delegate = null;
127                 // The configured state of the extension element representing this arithmetic function.
128                 private IConfigurationElement element;
129                 // Whether this function has been invoked before. 
130                 // Used for lazy evaluation of the service.
131                 private boolean invoked = false;
132
133                 /**
134                  * Construct a virtual proxy to stand in place of an extension function.
135                  * The constructor simply keeps track of an arithmetic function's configured state
136                  * without at this time instantiating the implementation of the function.
137                  * 
138                  * @param element The configuration of this arithmetic function.
139                  */
140                 public MetadataFunctionProxy(IConfigurationElement element) {
141                         this.element = element;
142                 }
143
144                 /**
145                  * Compute the function value. 
146                  * The proxy computation first instantiates the implementation
147                  * of the function, if this is the first time the function is called,
148                  * and then delegates to that implementation. The instantiation and
149                  * initialization of the delegate implementation uses the standard 
150                  * callback object instantiation and initialization methods of Eclipse.
151                  * 
152                  * @see com.bolour.sample.eclipse.service.ui.IFunction#compute(long)
153                  */
154                 public final void run(Document doc) {
155                         try {
156                                 getDelegate().run(doc);
157                         } catch (Exception e) {
158                                 // TODO Auto-generated catch block
159                                 e.printStackTrace();
160                         }
161                 }
162
163                 /**
164                  * Instantiate and initialize the implementation of the function if
165                  * this is the first time the proxy has been called.
166                  * 
167                  * @return The implementation delegate (same as the instance variable <code>delegate</code>.
168                  * @throws Exception If the callback object is misconfigured.
169                  */
170                 private final IMetadataExtension getDelegate() throws Exception {
171                         if (invoked) {
172                                 return delegate;
173                         }
174                         invoked = true;
175                         try {
176                                 Object callback =
177                                         element.createExecutableExtension(CLASS_ATTRIBUTE);
178                                 if (!(callback instanceof IMetadataExtension)) {
179                                         String message =
180                                                 "callback class '"
181                                                         + callback.getClass().getName()
182                                                         + "' is not an IFunction";
183                                         System.err.println(message);
184                                         throw new ClassCastException(message);
185                                 }
186                                 delegate = (IMetadataExtension) callback;
187                         } catch (CoreException ex) {
188                                 System.err.println(ex.getMessage());
189                                 ex.printStackTrace();
190                                 throw ex;
191                         } catch (Error err) {
192                                 System.err.println(err.getMessage());
193                                 err.printStackTrace();
194                                 throw err;
195                         }
196                         return delegate;
197                 }
198         }
199         /**
200          * Virtual proxy class for function invokation.
201          * Members of this class support lazy processing by fronting the real 
202          * implementations of arithmetic functions configured into extensions.
203          */
204         private static class DataFunctionProxy implements IDataExtension {
205                 // The "real" implementation of the function.
206                 private IDataExtension delegate = null;
207                 // The configured state of the extension element representing this arithmetic function.
208                 private IConfigurationElement element;
209                 // Whether this function has been invoked before. 
210                 // Used for lazy evaluation of the service.
211                 private boolean invoked = false;
212
213                 /**
214                  * Construct a virtual proxy to stand in place of an extension function.
215                  * The constructor simply keeps track of an arithmetic function's configured state
216                  * without at this time instantiating the implementation of the function.
217                  * 
218                  * @param element The configuration of this arithmetic function.
219                  */
220                 public DataFunctionProxy(IConfigurationElement element) {
221                         this.element = element;
222                 }
223
224                 /**
225                  * Compute the function value. 
226                  * The proxy computation first instantiates the implementation
227                  * of the function, if this is the first time the function is called,
228                  * and then delegates to that implementation. The instantiation and
229                  * initialization of the delegate implementation uses the standard 
230                  * callback object instantiation and initialization methods of Eclipse.
231                  * 
232                  * @see com.bolour.sample.eclipse.service.ui.IFunction#compute(long)
233                  */
234                 public final void run(Document doc) {
235                         try {
236                                 getDelegate().run(doc);
237                         } catch (Exception e) {
238                                 // TODO Auto-generated catch block
239                                 e.printStackTrace();
240                         }
241                 }
242
243                 /**
244                  * Instantiate and initialize the implementation of the function if
245                  * this is the first time the proxy has been called.
246                  * 
247                  * @return The implementation delegate (same as the instance variable <code>delegate</code>.
248                  * @throws Exception If the callback object is misconfigured.
249                  */
250                 private final IDataExtension getDelegate() throws Exception {
251                         if (invoked) {
252                                 return delegate;
253                         }
254                         invoked = true;
255                         try {
256                                 Object callback =
257                                         element.createExecutableExtension(CLASS_ATTRIBUTE);
258                                 if (!(callback instanceof IDataExtension)) {
259                                         String message =
260                                                 "callback class '"
261                                                         + callback.getClass().getName()
262                                                         + "' is not an IFunction";
263                                         System.err.println(message);
264                                         throw new ClassCastException(message);
265                                 }
266                                 delegate = (IDataExtension) callback;
267                         } catch (CoreException ex) {
268                                 System.err.println(ex.getMessage());
269                                 ex.printStackTrace();
270                                 throw ex;
271                         } catch (Error err) {
272                                 System.err.println(err.getMessage());
273                                 err.printStackTrace();
274                                 throw err;
275                         }
276                         return delegate;
277                 }
278         }
279
280 }
281