001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041: package org.netbeans.modules.visualweb.insync.live;
042:
043: import javax.lang.model.element.ExecutableElement;
044: import org.netbeans.modules.visualweb.insync.java.ClassUtil;
045: import org.netbeans.modules.visualweb.insync.java.JavaClass;
046: import java.util.ArrayList;
047: import java.util.List;
048: import org.netbeans.modules.visualweb.insync.java.Method;
049: import org.netbeans.modules.visualweb.insync.java.ReadTaskWrapper;
050: import org.openide.util.NbBundle;
051: import com.sun.rave.designtime.ContextMethod;
052: import com.sun.source.tree.MethodTree;
053: import javax.lang.model.element.Modifier;
054: import javax.lang.model.element.VariableElement;
055: import org.netbeans.api.java.source.CompilationInfo;
056: import org.netbeans.modules.visualweb.insync.java.TreeUtils;
057:
058: /**
059: *
060: * This class provides the implementation for Design time ContextMethod APIs
061: *
062: * @author jdeva
063: *
064: */
065: public class ContextMethodHelper {
066: LiveUnit lu;
067:
068: public ContextMethodHelper(LiveUnit lu) {
069: this .lu = lu;
070: }
071:
072: /**
073: * Returns a set of {@link ContextMethod} objects describing the public methods declared on this
074: * DesignContext (source file).
075: *
076: * @return An array of {@link ContextMethod} objects, describing the public methods declared on
077: * this DesignContext (source file)
078: */
079: public ContextMethod[] getContextMethods() {
080: JavaClass javaClass = lu.getSourceUnit().getThisClass();
081: ArrayList contextMethods = new ArrayList();
082:
083: //Go through all the available methods
084: for (Method m : javaClass.getMethods()) {
085: //Construct a ContextMethod object
086: ContextMethod cm = getContextMethod(m);
087: if (cm != null)
088: contextMethods.add(cm);
089: }
090: return (ContextMethod[]) contextMethods
091: .toArray(new ContextMethod[0]);
092: }
093:
094: /**
095: * Returns a {@link ContextMethod} object describing the public method with the specified name
096: * and parameter types. Returns <code>null</code> if no public method exists on this
097: * DesignContext with the specified name and parameter types.
098: *
099: * @param methodName The method name of the desired context method
100: * @param parameterTypes The parameter types of the desired context method
101: * @return A ContextMethod object describing the requested method, or <code>null</code> if no
102: * method exists with the specified name and parameter types
103: */
104: public ContextMethod getContextMethod(final Method m) {
105: return (ContextMethod) ReadTaskWrapper.execute(
106: new ReadTaskWrapper.Read() {
107: public Object run(CompilationInfo cinfo) {
108: ExecutableElement elem = m.getElement(cinfo);
109: if (elem.getModifiers().contains(
110: Modifier.PUBLIC)) {
111: List<? extends VariableElement> params = elem
112: .getParameters();
113: Class[] paramTypes = new Class[params
114: .size()];
115: String[] paramNames = new String[params
116: .size()];
117: int i = 0;
118: ClassLoader cl = lu.getSourceUnit()
119: .getClassLoader();
120: try {
121: for (VariableElement param : params) {
122: paramTypes[i] = ClassUtil.getClass(
123: param.asType().toString(),
124: cl);
125: paramNames[i++] = param
126: .getSimpleName().toString();
127: }
128: MethodTree tree = cinfo.getTrees()
129: .getTree(elem);
130: Class retType = ClassUtil
131: .getClass(elem.getReturnType()
132: .toString(), cl);
133: return new ContextMethod(lu, elem
134: .getSimpleName().toString(), m
135: .getModifierFlags(tree),
136: retType, paramTypes,
137: paramNames, Method.getBodyText(
138: cinfo, tree), m
139: .getCommentText(cinfo,
140: tree));
141: } catch (ClassNotFoundException cnfe) {
142: }
143: }
144: return null;
145: }
146: }, lu.getSourceUnit().getJavaUnit().getFileObject());
147: }
148:
149: /**
150: * Returns a {@link ContextMethod} object describing the public method with the specified name
151: * and no arguments. Returns <code>null</code> if no public method exists on this
152: * DesignContext with the specified name and no arguments.
153: *
154: * @param methodName The method name of the desired context method
155: * @return A ContextMethod object describing the requested method, or <code>null</code> if no
156: * method exists with the specified name and no arguments
157: */
158: public ContextMethod getContextMethod(String methodName) {
159: return getContextMethod(methodName, null);
160: }
161:
162: /**
163: * Returns a {@link ContextMethod} object describing the public method with the specified name
164: * which doesn't take anyparameter types. Returns <code>null</code> if no public method exists on this
165: * DesignContext with the specified name and parameter types.
166: *
167: * @param methodName The method name of the desired context method
168: * @param parameterTypes The parameter types of the desired context method
169: * @return A ContextMethod object describing the requested method, or <code>null</code> if no
170: * method exists with the specified name and parameter types
171: */
172: public ContextMethod getContextMethod(String methodName,
173: Class[] parameterTypes) {
174: JavaClass javaClass = lu.getSourceUnit().getThisClass();
175: Method m = javaClass.getMethod(methodName, parameterTypes);
176: return getContextMethod(m);
177: }
178:
179: /**
180: * <p>Creates a new public method in the source code for this DesignContext. The passed
181: * ContextMethod <strong>must</strong> specify at least the designContext and methodName, and
182: * <strong>must not</strong> describe a method that already exists in the DesignContext source.
183: * To update an existing method, use the <code>updateContextMethod()</code> method. These
184: * methods are separated to help prevent accidental method overwriting. The following table
185: * details how the specified ContextMethod is used for this method:</p>
186: *
187: * <p><table border="1">
188: * <tr><th>designContext <td><strong>REQUIRED.</strong> Must match the DesignContext that is
189: * being called. This is essentially a safety precaution to help prevent accidental
190: * method overwriting.
191: * <tr><th>methodName <td><strong>REQUIRED.</strong> Defines the method name.
192: * <tr><th>parameterTypes <td>Defines the parameter types. If <code>null</code> or an empty
193: * array is specified, the created method will have no arguments.
194: * <tr><th>parameterNames <td>Defines the parameter names. If <code>null</code> or an empty
195: * array is specified (or an array shorter than the parameterTypes array), default
196: * argument names will be used.
197: * <tr><th>returnType <td>Defines the return type. If <code>null</code> is specified, the
198: * created method will have a <code>void</code> return type.
199: * <tr><th>throwsTypes <td>Defines the throws clause types. If <code>null</code> is specified,
200: * the created method will have no throws clause.
201: * <tr><th>bodySource <td>Defines the method body Java source code. If <code>null</code> is
202: * specified, the method will have an empty body. If the value is non-null, this must
203: * represent valid (compilable) Java source code.
204: * <tr><th>commentText <td>Defines the comment text above the newly created method. If
205: * <code>null</code> is specified, no comment text will be included.
206: * </table></p>
207: *
208: * @param method A ContextMethod object representing the desired public method.
209: * @return <code>true</code> if the method was created successfully, or <code>false</code> if
210: * it was not.
211: * @throws IllegalArgumentException If there was a syntax error in any of the ContextMethod
212: * settings, or if the ContextMethod represents a method that already exists on this
213: * DesignContext (<code>updateContextMethod()</code> must be used in this case to avoid
214: * accidental method overwriting)
215: */
216: public boolean createContextMethod(ContextMethod method)
217: throws IllegalArgumentException {
218: if (method == null || method.getDesignContext() != lu)
219: return false;
220: JavaClass javaClass = lu.getSourceUnit().getThisClass();
221: Method m = javaClass.getPublicMethod(method.getName(), method
222: .getParameterTypes());
223: if (m != null)
224: throw new IllegalArgumentException(NbBundle.getMessage(
225: LiveUnit.class, "IllegalMethod")); //NOI18N;
226:
227: //Add the new method at the end
228: m = javaClass.addMethod(method);
229: if (m != null) {
230: //Check if there are errors because of adding method
231: if (lu.getSourceUnit().getJavaUnit().getErrors().length > 0)
232: throw new IllegalArgumentException(NbBundle.getMessage(
233: LiveUnit.class, "IllegalSource")); //NOI18N;
234: return true;
235: }
236: return false;
237: }
238:
239: /**
240: * <p>Updates an existing public method in the source code for this DesignContext. The passed
241: * ContextMethod will be used to locate the desired public method to update using the
242: * designContext, methodName, and parameterTypes. This method may only be used to update the
243: * parameterNames, returnType, throwsTypes, bodySource, or commentText. Any other changes
244: * actually constitute the creation of a new method, as they alter the method signature. To
245: * create a new method, the <code>createContextMethod()</code> method should be used. These
246: * operations are separated to help prevent accidental method overwriting. The following table
247: * details how the specified ContextMethod is used for this method:</p>
248: *
249: * <p><table border="1">
250: * <tr><th>designContext <td><strong>REQUIRED.</strong> Must match the DesignContext that is
251: * being called. This is essentially a safety precaution to help prevent accidental
252: * method overwriting.
253: * <tr><th>methodName <td><strong>REQUIRED.</strong> Specifies the desired method name.
254: * <tr><th>parameterTypes <td><strong>REQUIRED.</strong> Specifies the desired method's
255: * parameter types (if it has any). If <code>null</code> or an empty array is
256: * specified, the desired method is assumed to have zero arguments.
257: * <tr><th>parameterNames <td>Defines the parameter names. If <code>null</code> or an empty
258: * array is specified (or an array shorter than the parameterTypes array), default
259: * argument names will be used.
260: * <tr><th>returnType <td>Defines the method's return type. If <code>null</code> is specified,
261: * the method is assumed to have a <code>void</code> return type.
262: * <tr><th>throwsTypes <td>Defines the throws clause types. If <code>null</code> is specified,
263: * the resulting method will have no throws clause.
264: * <tr><th>bodySource <td>Defines the method body Java source code. If <code>null</code> is
265: * specified, the resulting method body will be empty. If the value is non-null, this
266: * must represent valid (compilable) Java source code. Note that a method with a
267: * non-void return type <strong>must</strong> return a value.
268: * <tr><th>commentText <td>Defines the comment text above the newly created method. If
269: * <code>null</code> is specified, no comment text will be included.
270: * </table></p>
271: *
272: * @param method The desired ContextMethod representing the method to be updated
273: * @return The resulting ContextMethod object (including any updates from the process)
274: * @throws IllegalArgumentException If there was a syntax error in any of the ContextMethod
275: * settings, or if the ContextMethod does not exist in this DesignContext.
276: */
277: public ContextMethod updateContextMethod(ContextMethod method)
278: throws IllegalArgumentException {
279: if (method == null || method.getDesignContext() != lu)
280: return null;
281:
282: JavaClass javaClass = lu.getSourceUnit().getThisClass();
283: Class[] paramTypes = method.getParameterTypes();
284: Method m = javaClass.getPublicMethod(method.getName(),
285: paramTypes);
286: if (m != null) {
287: m.update(method);
288: //Check if there are errors because of updating method
289: /*
290: if(lu.getSourceUnit().getJavaUnit().getErrors().length > 0)
291: throw new IllegalArgumentException(
292: NbBundle.getMessage(LiveUnit.class, "IllegalSource")); //NOI18N;
293: */
294: ContextMethod retVal = getContextMethod(m);
295: return retVal;
296: } else {
297: throw new IllegalArgumentException(NbBundle.getMessage(
298: LiveUnit.class, "IllegalMethod")); //NOI18N;
299: }
300: }
301:
302: /**
303: * <p>Removes an existing method from the source code for this DesignContext. The passed
304: * ContextMethod will be used to locate the desired method to remove using the designContext,
305: * methodName, and parameterTypes. No other portions of the ContextMethod are used. The
306: * following table details how the specified ContextMethod is used for this method:</p>
307: *
308: * <p><table border="1">
309: * <tr><th>designContext <td><strong>REQUIRED.</strong> Must match the DesignContext that is
310: * being called. This is essentially a safety precaution to help prevent accidental
311: * method removal.
312: * <tr><th>methodName <td><strong>REQUIRED.</strong> Specifies the desired method name.
313: * <tr><th>parameterTypes <td><strong>REQUIRED.</strong> Specifies the desired method's
314: * parameter types (if it has any). If <code>null</code> or an empty array is
315: * specified, the desired method is assumed to have zero arguments.
316: * <tr><th>parameterNames <td>Ignored.
317: * <tr><th>returnType <td>Ignored.
318: * <tr><th>throwsTypes <td>Ignored.
319: * <tr><th>bodySource <td>Ignored.
320: * <tr><th>commentText <td>Ignored.
321: * </table></p>
322: *
323: * @param method A ContextMethod object defining the method to be removed
324: * @return <code>true</code> if the method was successfully removed
325: * @exception IllegalArgumentException if the specified ContextMethod does not exist or is not
326: * public on this DesignContext
327: */
328: public boolean removeContextMethod(ContextMethod method) {
329: if (method == null || method.getDesignContext() != lu)
330: return false;
331:
332: JavaClass javaClass = lu.getSourceUnit().getThisClass();
333: Class[] paramTypes = method.getParameterTypes();
334: if (paramTypes == null)
335: paramTypes = new Class[0];
336: Method m = javaClass.getPublicMethod(method.getName(),
337: paramTypes);
338: if (m != null) {
339: m.remove();
340: } else {
341: throw new IllegalArgumentException(NbBundle.getMessage(
342: LiveUnit.class, "IllegalMethod")); //NOI18N;
343: }
344: return true;
345: }
346: }
|