1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   *
12   *
13   */
14  
15  package com.liferay.portal.action;
16  
17  import com.liferay.portal.kernel.json.JSONArray;
18  import com.liferay.portal.kernel.json.JSONException;
19  import com.liferay.portal.kernel.json.JSONFactoryUtil;
20  import com.liferay.portal.kernel.json.JSONObject;
21  import com.liferay.portal.kernel.log.Log;
22  import com.liferay.portal.kernel.log.LogFactoryUtil;
23  import com.liferay.portal.kernel.util.ArrayUtil;
24  import com.liferay.portal.kernel.util.GetterUtil;
25  import com.liferay.portal.kernel.util.ListUtil;
26  import com.liferay.portal.kernel.util.MethodHandler;
27  import com.liferay.portal.kernel.util.MethodKey;
28  import com.liferay.portal.kernel.util.ParamUtil;
29  import com.liferay.portal.kernel.util.StringUtil;
30  import com.liferay.portal.kernel.util.Validator;
31  import com.liferay.portal.model.BaseModel;
32  import com.liferay.portal.service.ServiceContext;
33  import com.liferay.portal.service.ServiceContextUtil;
34  import com.liferay.portal.struts.JSONAction;
35  import com.liferay.portal.util.PropsValues;
36  import com.liferay.portlet.tags.model.TagsAssetDisplay;
37  import com.liferay.portlet.tags.model.TagsAssetType;
38  
39  import java.lang.reflect.InvocationTargetException;
40  import java.lang.reflect.Method;
41  
42  import java.util.Arrays;
43  import java.util.Date;
44  import java.util.HashMap;
45  import java.util.HashSet;
46  import java.util.List;
47  import java.util.Map;
48  import java.util.Set;
49  
50  import javax.servlet.http.HttpServletRequest;
51  import javax.servlet.http.HttpServletResponse;
52  
53  import org.apache.struts.action.ActionForm;
54  import org.apache.struts.action.ActionMapping;
55  
56  /**
57   * <a href="JSONServiceAction.java.html"><b><i>View Source</i></b></a>
58   *
59   * @author Brian Wing Shun Chan
60   * @author Karthik Sudarshan
61   */
62  public class JSONServiceAction extends JSONAction {
63  
64      public JSONServiceAction() {
65          _invalidClassNames.addAll(
66              ListUtil.fromArray(PropsValues.JSON_SERVICE_INVALID_CLASS_NAMES));
67  
68          if (_log.isDebugEnabled()) {
69              for (String invalidClassName : _invalidClassNames) {
70                  _log.debug("Invalid class name " + invalidClassName);
71              }
72          }
73      }
74  
75      public String getJSON(
76              ActionMapping mapping, ActionForm form, HttpServletRequest request,
77              HttpServletResponse response)
78          throws Exception {
79  
80          String className = ParamUtil.getString(request, "serviceClassName");
81          String methodName = ParamUtil.getString(request, "serviceMethodName");
82          String[] serviceParameters = getStringArrayFromJSON(
83              request, "serviceParameters");
84          String[] serviceParameterTypes = getStringArrayFromJSON(
85              request, "serviceParameterTypes");
86  
87          if (!isValidRequest(request)) {
88              return null;
89          }
90  
91          Thread currentThread = Thread.currentThread();
92  
93          ClassLoader contextClassLoader = currentThread.getContextClassLoader();
94  
95          Class<?> classObj = contextClassLoader.loadClass(className);
96  
97          Object[] methodAndParameterTypes = getMethodAndParameterTypes(
98              classObj, methodName, serviceParameters, serviceParameterTypes);
99  
100         if (methodAndParameterTypes != null) {
101             Method method = (Method)methodAndParameterTypes[0];
102             Class<?>[] parameterTypes = (Class[])methodAndParameterTypes[1];
103             Object[] args = new Object[serviceParameters.length];
104 
105             for (int i = 0; i < serviceParameters.length; i++) {
106                 args[i] = getArgValue(
107                     request, classObj, methodName, serviceParameters[i],
108                     parameterTypes[i]);
109             }
110 
111             try {
112                 if (_log.isDebugEnabled()) {
113                     _log.debug(
114                         "Invoking " + classObj + " on method " +
115                             method.getName() + " with args " +
116                                 Arrays.toString(args));
117                 }
118 
119                 Object returnObj = method.invoke(classObj, args);
120 
121                 if (returnObj != null) {
122                     return getReturnValue(returnObj, method.getReturnType());
123                 }
124                 else {
125                     JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
126 
127                     return jsonObject.toString();
128                 }
129             }
130             catch (Exception e) {
131                 if (_log.isDebugEnabled()) {
132                     _log.debug(
133                         "Invoked " + classObj + " on method " +
134                             method.getName() + " with args " +
135                                 Arrays.toString(args),
136                         e);
137                 }
138 
139                 JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
140 
141                 if (e instanceof InvocationTargetException) {
142                     jsonObject.put("exception", e.getCause().toString());
143                 }
144                 else {
145                     jsonObject.put("exception", e.getMessage());
146                 }
147 
148                 return jsonObject.toString();
149             }
150         }
151 
152         return null;
153     }
154 
155     protected Object getArgValue(
156             HttpServletRequest request, Class<?> classObj, String methodName,
157             String parameter, Class<?> parameterType)
158         throws Exception {
159 
160         String parameterTypeName = parameterType.getName();
161 
162         String value = ParamUtil.getString(request, parameter);
163 
164         if (Validator.isNull(value) &&
165             !parameterTypeName.equals("[Ljava.lang.String;")) {
166 
167             return null;
168         }
169         else if (parameterTypeName.equals("boolean") ||
170                  parameterTypeName.equals(Boolean.class.getName())) {
171 
172             return Boolean.valueOf(ParamUtil.getBoolean(request, parameter));
173         }
174         else if (parameterTypeName.equals("double") ||
175                  parameterTypeName.equals(Double.class.getName())) {
176 
177             return new Double(ParamUtil.getDouble(request, parameter));
178         }
179         else if (parameterTypeName.equals("int") ||
180                  parameterTypeName.equals(Integer.class.getName())) {
181 
182             return new Integer(ParamUtil.getInteger(request, parameter));
183         }
184         else if (parameterTypeName.equals("long") ||
185                  parameterTypeName.equals(Long.class.getName())) {
186 
187             return new Long(ParamUtil.getLong(request, parameter));
188         }
189         else if (parameterTypeName.equals("short") ||
190                  parameterTypeName.equals(Short.class.getName())) {
191 
192             return new Short(ParamUtil.getShort(request, parameter));
193         }
194         else if (parameterTypeName.equals(Date.class.getName())) {
195             return new Date(ParamUtil.getLong(request, parameter));
196         }
197         else if (parameterTypeName.equals(ServiceContext.class.getName())) {
198             JSONObject jsonObject = JSONFactoryUtil.createJSONObject(value);
199 
200             jsonObject.put("javaClass", ServiceContext.class.getName());
201 
202             return ServiceContextUtil.deserialize(jsonObject);
203         }
204         else if (parameterTypeName.equals(String.class.getName())) {
205             return value;
206         }
207         else if (parameterTypeName.equals("[Z")) {
208             return ParamUtil.getBooleanValues(request, parameter);
209         }
210         else if (parameterTypeName.equals("[D")) {
211             return ParamUtil.getDoubleValues(request, parameter);
212         }
213         else if (parameterTypeName.equals("[F")) {
214             return ParamUtil.getFloatValues(request, parameter);
215         }
216         else if (parameterTypeName.equals("[I")) {
217             return ParamUtil.getIntegerValues(request, parameter);
218         }
219         else if (parameterTypeName.equals("[J")) {
220             return ParamUtil.getLongValues(request, parameter);
221         }
222         else if (parameterTypeName.equals("[S")) {
223             return ParamUtil.getShortValues(request, parameter);
224         }
225         else if (parameterTypeName.equals("[Ljava.lang.String;")) {
226             return StringUtil.split(value);
227         }
228         else if (parameterTypeName.equals("[[Z")) {
229             String[] values = request.getParameterValues(parameter);
230 
231             if ((values != null) && (values.length > 0)) {
232                 String[] values0 = StringUtil.split(values[0]);
233 
234                 boolean[][] doubleArray =
235                     new boolean[values.length][values0.length];
236 
237                 for (int i = 0; i < values.length; i++) {
238                     String[] curValues = StringUtil.split(values[i]);
239 
240                     for (int j = 0; j < curValues.length; j++) {
241                         doubleArray[i][j] = GetterUtil.getBoolean(curValues[j]);
242                     }
243                 }
244 
245                 return doubleArray;
246             }
247             else {
248                 return new boolean[0][0];
249             }
250         }
251         else if (parameterTypeName.equals("[[D")) {
252             String[] values = request.getParameterValues(parameter);
253 
254             if ((values != null) && (values.length > 0)) {
255                 String[] values0 = StringUtil.split(values[0]);
256 
257                 double[][] doubleArray =
258                     new double[values.length][values0.length];
259 
260                 for (int i = 0; i < values.length; i++) {
261                     String[] curValues = StringUtil.split(values[i]);
262 
263                     for (int j = 0; j < curValues.length; j++) {
264                         doubleArray[i][j] = GetterUtil.getDouble(curValues[j]);
265                     }
266                 }
267 
268                 return doubleArray;
269             }
270             else {
271                 return new double[0][0];
272             }
273         }
274         else if (parameterTypeName.equals("[[F")) {
275             String[] values = request.getParameterValues(parameter);
276 
277             if ((values != null) && (values.length > 0)) {
278                 String[] values0 = StringUtil.split(values[0]);
279 
280                 float[][] doubleArray =
281                     new float[values.length][values0.length];
282 
283                 for (int i = 0; i < values.length; i++) {
284                     String[] curValues = StringUtil.split(values[i]);
285 
286                     for (int j = 0; j < curValues.length; j++) {
287                         doubleArray[i][j] = GetterUtil.getFloat(curValues[j]);
288                     }
289                 }
290 
291                 return doubleArray;
292             }
293             else {
294                 return new float[0][0];
295             }
296         }
297         else if (parameterTypeName.equals("[[I")) {
298             String[] values = request.getParameterValues(parameter);
299 
300             if ((values != null) && (values.length > 0)) {
301                 String[] values0 = StringUtil.split(values[0]);
302 
303                 int[][] doubleArray =
304                     new int[values.length][values0.length];
305 
306                 for (int i = 0; i < values.length; i++) {
307                     String[] curValues = StringUtil.split(values[i]);
308 
309                     for (int j = 0; j < curValues.length; j++) {
310                         doubleArray[i][j] = GetterUtil.getInteger(curValues[j]);
311                     }
312                 }
313 
314                 return doubleArray;
315             }
316             else {
317                 return new int[0][0];
318             }
319         }
320         else if (parameterTypeName.equals("[[J")) {
321             String[] values = request.getParameterValues(parameter);
322 
323             if ((values != null) && (values.length > 0)) {
324                 String[] values0 = StringUtil.split(values[0]);
325 
326                 long[][] doubleArray =
327                     new long[values.length][values0.length];
328 
329                 for (int i = 0; i < values.length; i++) {
330                     String[] curValues = StringUtil.split(values[i]);
331 
332                     for (int j = 0; j < curValues.length; j++) {
333                         doubleArray[i][j] = GetterUtil.getLong(curValues[j]);
334                     }
335                 }
336 
337                 return doubleArray;
338             }
339             else {
340                 return new long[0][0];
341             }
342         }
343         else if (parameterTypeName.equals("[[S")) {
344             String[] values = request.getParameterValues(parameter);
345 
346             if ((values != null) && (values.length > 0)) {
347                 String[] values0 = StringUtil.split(values[0]);
348 
349                 short[][] doubleArray =
350                     new short[values.length][values0.length];
351 
352                 for (int i = 0; i < values.length; i++) {
353                     String[] curValues = StringUtil.split(values[i]);
354 
355                     for (int j = 0; j < curValues.length; j++) {
356                         doubleArray[i][j] = GetterUtil.getShort(curValues[j]);
357                     }
358                 }
359 
360                 return doubleArray;
361             }
362             else {
363                 return new short[0][0];
364             }
365         }
366         else if (parameterTypeName.equals("[[Ljava.lang.String")) {
367             String[] values = request.getParameterValues(parameter);
368 
369             if ((values != null) && (values.length > 0)) {
370                 String[] values0 = StringUtil.split(values[0]);
371 
372                 String[][] doubleArray =
373                     new String[values.length][values0.length];
374 
375                 for (int i = 0; i < values.length; i++) {
376                     doubleArray[i] = StringUtil.split(values[i]);
377                 }
378 
379                 return doubleArray;
380             }
381             else {
382                 return new String[0][0];
383             }
384         }
385         else {
386             _log.error(
387                 "Unsupported parameter type for class " + classObj +
388                     ", method " + methodName + ", parameter " + parameter +
389                         ", and type " + parameterTypeName);
390 
391             return null;
392         }
393     }
394 
395     protected Object[] getMethodAndParameterTypes(
396             Class<?> classObj, String methodName, String[] parameters,
397             String[] parameterTypes)
398         throws Exception {
399 
400         String parameterNames = StringUtil.merge(parameters);
401 
402         String key =
403             classObj.getName() + "_METHOD_NAME_" + methodName +
404                 "_PARAMETERS_" + parameterNames;
405 
406         Object[] methodAndParameterTypes = _methodCache.get(key);
407 
408         if (methodAndParameterTypes != null) {
409             return methodAndParameterTypes;
410         }
411 
412         Method method = null;
413         Class<?>[] methodParameterTypes = null;
414 
415         Method[] methods = classObj.getMethods();
416 
417         for (int i = 0; i < methods.length; i++) {
418             Method curMethod = methods[i];
419 
420             if (curMethod.getName().equals(methodName)) {
421                 Class<?>[] curParameterTypes = curMethod.getParameterTypes();
422 
423                 if (curParameterTypes.length == parameters.length) {
424                     if ((parameterTypes.length > 0) &&
425                         (parameterTypes.length == curParameterTypes.length)) {
426 
427                         boolean match = true;
428 
429                         for (int j = 0; j < parameterTypes.length; j++) {
430                             String t1 = parameterTypes[j];
431                             String t2 = curParameterTypes[j].getName();
432 
433                             if (!t1.equals(t2)) {
434                                 match = false;
435                             }
436                         }
437 
438                         if (match) {
439                             method = curMethod;
440                             methodParameterTypes = curParameterTypes;
441 
442                             break;
443                         }
444                     }
445                     else if (method != null) {
446                         _log.error(
447                             "Obscure method name for class " + classObj +
448                                 ", method " + methodName + ", and parameters " +
449                                     parameterNames);
450 
451                         return null;
452                     }
453                     else {
454                         method = curMethod;
455                         methodParameterTypes = curParameterTypes;
456                     }
457                 }
458             }
459         }
460 
461         if (method != null) {
462             methodAndParameterTypes = new Object[] {
463                 method, methodParameterTypes
464             };
465 
466             _methodCache.put(key, methodAndParameterTypes);
467 
468             return methodAndParameterTypes;
469         }
470         else {
471             _log.error(
472                 "No method found for class " + classObj + ", method " +
473                     methodName + ", and parameters " + parameterNames);
474 
475             return null;
476         }
477     }
478 
479     protected String getReturnValue(Object returnObj, Class<?> returnType)
480         throws Exception {
481 
482         if ((returnObj instanceof Boolean) || (returnObj instanceof Double) ||
483             (returnObj instanceof Integer) || (returnObj instanceof Long) ||
484             (returnObj instanceof Short) || (returnObj instanceof String)) {
485 
486             JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
487 
488             jsonObject.put("returnValue", returnObj.toString());
489 
490             return jsonObject.toString();
491         }
492         else if (returnObj instanceof BaseModel<?>) {
493             String serlializerClassName = getSerializerClassName(returnObj);
494 
495             MethodKey methodKey = new MethodKey(
496                 serlializerClassName, "toJSONObject", returnType);
497 
498             MethodHandler methodHandler = new MethodHandler(
499                 methodKey, returnObj);
500 
501             JSONObject jsonObject = (JSONObject)methodHandler.invoke(false);
502 
503             return jsonObject.toString();
504         }
505         else if (returnObj instanceof BaseModel<?>[]) {
506             JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
507 
508             BaseModel<?>[] returnArray = (BaseModel[])returnObj;
509 
510             if (returnArray.length > 0) {
511                 BaseModel<?> returnItem0 = returnArray[0];
512 
513                 String serializerClassName = getSerializerClassName(
514                     returnItem0);
515 
516                 MethodKey methodKey = new MethodKey(
517                     serializerClassName, "toJSONArray", returnType);
518 
519                 MethodHandler methodHandler = new MethodHandler(
520                     methodKey, returnObj);
521 
522                 jsonArray = (JSONArray)methodHandler.invoke(false);
523             }
524 
525             return jsonArray.toString();
526         }
527         else if (returnObj instanceof BaseModel<?>[][]) {
528             JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
529 
530             BaseModel<?>[][] returnArray = (BaseModel<?>[][])returnObj;
531 
532             if ((returnArray.length > 0) &&
533                 (returnArray[0].length > 0)) {
534 
535                 BaseModel<?> returnItem0 = returnArray[0][0];
536 
537                 String serializerClassName = getSerializerClassName(
538                     returnItem0);
539 
540                 MethodKey methodKey = new MethodKey(
541                     serializerClassName, "toJSONArray", returnType);
542 
543                 MethodHandler methodHandler = new MethodHandler(
544                     methodKey, returnObj);
545 
546                 jsonArray = (JSONArray)methodHandler.invoke(false);
547             }
548 
549             return jsonArray.toString();
550         }
551         else if (returnObj instanceof List<?>) {
552             JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
553 
554             List<Object> returnList = (List<Object>)returnObj;
555 
556             if (!returnList.isEmpty()) {
557                 Object returnItem0 = returnList.get(0);
558 
559                 String serlializerClassName = getSerializerClassName(
560                     returnItem0);
561 
562                 MethodKey methodKey = new MethodKey(
563                     serlializerClassName, "toJSONArray", returnType);
564 
565                 MethodHandler methodHandler = new MethodHandler(
566                     methodKey, returnObj);
567 
568                 jsonArray = (JSONArray)methodHandler.invoke(false);
569             }
570 
571             return jsonArray.toString();
572         }
573         else if (returnObj instanceof JSONArray) {
574             JSONArray jsonArray = (JSONArray)returnObj;
575 
576             return jsonArray.toString();
577         }
578         else if (returnObj instanceof JSONObject) {
579             JSONObject jsonObject = (JSONObject)returnObj;
580 
581             return jsonObject.toString();
582         }
583         else if (returnObj instanceof TagsAssetDisplay) {
584             return getReturnValue((TagsAssetDisplay)returnObj);
585         }
586         else if (returnObj instanceof TagsAssetDisplay[]) {
587             return getReturnValue((TagsAssetDisplay[])returnObj);
588         }
589         else if (returnObj instanceof TagsAssetType) {
590             return getReturnValue((TagsAssetType)returnObj);
591         }
592         else if (returnObj instanceof TagsAssetType[]) {
593             return getReturnValue((TagsAssetType[])returnObj);
594         }
595         else {
596             return JSONFactoryUtil.serialize(returnObj);
597         }
598     }
599 
600     protected String getReturnValue(TagsAssetDisplay assetDisplay)
601         throws Exception {
602 
603         JSONObject jsonObject = toJSONObject(assetDisplay);
604 
605         return jsonObject.toString();
606     }
607 
608     protected String getReturnValue(TagsAssetDisplay[] assetDisplays)
609         throws Exception {
610 
611         JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
612 
613         for (int i = 0; i < assetDisplays.length; i++) {
614             TagsAssetDisplay assetDisplay = assetDisplays[i];
615 
616             jsonArray.put(toJSONObject(assetDisplay));
617         }
618 
619         return jsonArray.toString();
620     }
621 
622     protected String getReturnValue(TagsAssetType assetType)
623         throws Exception {
624 
625         JSONObject jsonObject = toJSONObject(assetType);
626 
627         return jsonObject.toString();
628     }
629 
630     protected String getReturnValue(TagsAssetType[] assetTypes)
631         throws Exception {
632 
633         JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
634 
635         for (int i = 0; i < assetTypes.length; i++) {
636             TagsAssetType assetType = assetTypes[i];
637 
638             jsonArray.put(toJSONObject(assetType));
639         }
640 
641         return jsonArray.toString();
642     }
643 
644     protected String getSerializerClassName(Object obj) {
645         String serlializerClassName = StringUtil.replace(
646             obj.getClass().getName(),
647             new String[] {".model.impl.", "Impl"},
648             new String[] {".service.http.", "JSONSerializer"});
649 
650         return serlializerClassName;
651     }
652 
653     protected String[] getStringArrayFromJSON(
654             HttpServletRequest request, String param)
655         throws JSONException {
656 
657         String json = ParamUtil.getString(request, param, "[]");
658 
659         JSONArray jsonArray = JSONFactoryUtil.createJSONArray(json);
660 
661         return ArrayUtil.toStringArray(jsonArray);
662     }
663 
664     protected boolean isValidRequest(HttpServletRequest request) {
665         String className = ParamUtil.getString(request, "serviceClassName");
666 
667         if (className.contains(".service.") &&
668             className.endsWith("ServiceUtil") &&
669             !className.endsWith("LocalServiceUtil") &&
670             !_invalidClassNames.contains(className)) {
671 
672             return true;
673         }
674         else {
675             return false;
676         }
677     }
678 
679     protected JSONObject toJSONObject(TagsAssetDisplay assetDisplay) {
680         JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
681 
682         jsonObject.put("assetId", assetDisplay.getAssetId());
683         jsonObject.put("companyId", assetDisplay.getCompanyId());
684         jsonObject.put("userId", assetDisplay.getUserId());
685         jsonObject.put("userName", assetDisplay.getUserName());
686         jsonObject.put("createDate", assetDisplay.getCreateDate());
687         jsonObject.put("modifiedDate", assetDisplay.getModifiedDate());
688         jsonObject.put("classNameId", assetDisplay.getClassNameId());
689         jsonObject.put("className", assetDisplay.getClassName());
690         jsonObject.put("classPK", assetDisplay.getClassPK());
691         jsonObject.put("portletId", assetDisplay.getPortletId());
692         jsonObject.put("portletTitle", assetDisplay.getPortletTitle());
693         jsonObject.put("startDate", assetDisplay.getStartDate());
694         jsonObject.put("endDate", assetDisplay.getEndDate());
695         jsonObject.put("publishDate", assetDisplay.getPublishDate());
696         jsonObject.put("expirationDate", assetDisplay.getExpirationDate());
697         jsonObject.put("mimeType", assetDisplay.getMimeType());
698         jsonObject.put("title", assetDisplay.getTitle());
699         jsonObject.put("description", assetDisplay.getDescription());
700         jsonObject.put("summary", assetDisplay.getSummary());
701         jsonObject.put("url", assetDisplay.getUrl());
702         jsonObject.put("height", assetDisplay.getHeight());
703         jsonObject.put("width", assetDisplay.getWidth());
704         jsonObject.put("priority", assetDisplay.getPriority());
705         jsonObject.put("viewCount", assetDisplay.getViewCount());
706         jsonObject.put("tagsEntries", assetDisplay.getTagsEntries());
707 
708         return jsonObject;
709     }
710 
711     protected JSONObject toJSONObject(TagsAssetType assetType) {
712         JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
713 
714         jsonObject.put("classNameId", assetType.getClassNameId());
715         jsonObject.put("className", assetType.getClassName());
716         jsonObject.put("portletId", assetType.getPortletId());
717         jsonObject.put("portletTitle", assetType.getPortletTitle());
718 
719         return jsonObject;
720     }
721 
722     private static Log _log = LogFactoryUtil.getLog(JSONServiceAction.class);
723 
724     private Set<String> _invalidClassNames = new HashSet<String>();
725     private Map<String, Object[]> _methodCache =
726         new HashMap<String, Object[]>();
727 
728 }