View Javadoc
1   package org.andromda.cartridges.webservice.metafacades;
2   
3   import java.text.Collator;
4   import java.text.MessageFormat;
5   import java.util.ArrayList;
6   import java.util.Collection;
7   import java.util.Collections;
8   import java.util.Comparator;
9   import java.util.HashMap;
10  import java.util.HashSet;
11  import java.util.Iterator;
12  import java.util.LinkedHashSet;
13  import java.util.List;
14  import java.util.Map;
15  import java.util.Set;
16  import java.util.TreeMap;
17  import java.util.TreeSet;
18  import org.andromda.cartridges.webservice.WebServiceGlobals;
19  import org.andromda.cartridges.webservice.WebServiceUtils;
20  import org.andromda.core.common.ExceptionUtils;
21  import org.andromda.core.common.Introspector;
22  import org.andromda.core.metafacade.MetafacadeBase;
23  import org.andromda.core.metafacade.MetafacadeException;
24  import org.andromda.core.metafacade.ModelValidationMessage;
25  import org.andromda.metafacades.uml.AssociationEndFacade;
26  import org.andromda.metafacades.uml.AttributeFacade;
27  import org.andromda.metafacades.uml.ClassifierFacade;
28  import org.andromda.metafacades.uml.GeneralizableElementFacade;
29  import org.andromda.metafacades.uml.ModelElementFacade;
30  import org.andromda.metafacades.uml.OperationFacade;
31  import org.andromda.metafacades.uml.PackageFacade;
32  import org.andromda.metafacades.uml.ParameterFacade;
33  import org.andromda.metafacades.uml.Role;
34  import org.andromda.metafacades.uml.ServiceOperation;
35  import org.andromda.metafacades.uml.TypeMappings;
36  import org.andromda.metafacades.uml.UMLMetafacadeProperties;
37  import org.andromda.metafacades.uml.UMLProfile;
38  import org.andromda.translation.ocl.validation.OCLExpressions;
39  import org.andromda.translation.ocl.validation.OCLIntrospector;
40  import org.apache.commons.collections.Closure;
41  import org.apache.commons.collections.CollectionUtils;
42  import org.apache.commons.collections.Predicate;
43  import org.apache.commons.lang.ObjectUtils;
44  import org.apache.commons.lang.StringUtils;
45  import org.apache.log4j.Logger;
46  
47  /**
48   * MetafacadeLogic implementation for org.andromda.cartridges.webservice.metafacades.WebService.
49   *
50   * @see org.andromda.cartridges.webservice.metafacades.WebService
51   * @author Bob Fields
52   */
53  public class WebServiceLogicImpl
54      extends WebServiceLogic
55  {
56      private static final long serialVersionUID = 34L;
57      // ---------------- constructor -------------------------------
58      /**
59       * @param metaObject
60       * @param context
61       */
62      public WebServiceLogicImpl(
63          Object metaObject,
64          String context)
65      {
66          super(metaObject, context);
67      }
68  
69      /**
70       * The logger instance.
71       */
72      private static final Logger logger = Logger.getLogger(WebServiceLogicImpl.class);
73  
74      private static final String DEFAULT = "default";
75  
76      /**
77       * @return operations filtered by ((WebServiceOperation)object).isExposed()
78       * @see org.andromda.cartridges.webservice.metafacades.WebService#getAllowedOperations()
79       */
80      protected Collection<OperationFacade> handleGetAllowedOperations()
81      {
82          List<OperationFacade> operations = new ArrayList<OperationFacade>(this.getOperations());
83          CollectionUtils.filter(
84              operations,
85              new Predicate()
86              {
87                  public boolean evaluate(Object object)
88                  {
89                      boolean valid = WebServiceOperation.class.isAssignableFrom(object.getClass());
90                      if (valid)
91                      {
92                          valid = ((WebServiceOperation)object).isExposed();
93                      }
94                      return valid;
95                  }
96              });
97          if (this.getWSDLOperationSortMode().equals(OPERATION_SORT_MODE_NAME))
98          {
99              Collections.sort(
100                 operations,
101                 new OperationNameComparator());
102         }
103         return operations;
104     }
105 
106     /**
107      * @return this.getAllowedOperations() separated by " "
108      * @see org.andromda.cartridges.webservice.metafacades.WebService#getAllowedMethods()
109      */
110     protected String handleGetAllowedMethods()
111     {
112         Collection<String> methodNames = new ArrayList<String>();
113         Collection<WebServiceOperation> operations = this.getAllowedOperations();
114         if (operations != null && !operations.isEmpty())
115         {
116             for (WebServiceOperation operation : operations)
117             {
118                 methodNames.add(StringUtils.trimToEmpty(operation.getName()));
119             }
120         }
121         return StringUtils.join(
122             methodNames.iterator(),
123             " ");
124     }
125 
126     /**
127      * @return this.getName() formatted as this.getQualifiedNameLocalPartPattern()
128      * @see org.andromda.cartridges.webservice.metafacades.WebService#getQName()
129      */
130     protected String handleGetQName()
131     {
132         return MessageFormat.format(
133             this.getQualifiedNameLocalPartPattern(),
134                 StringUtils.trimToEmpty(this.getName()));
135     }
136 
137     /**
138      * @return this.getPackageName() reversed if this.isReverseNamespace()
139      * @see org.andromda.cartridges.webservice.metafacades.WebService#getNamespace()
140      */
141     protected String handleGetNamespace()
142     {
143         String packageName = this.getPackageName();
144         if (this.isReverseNamespace())
145         {
146             packageName = WebServiceUtils.reversePackage(packageName);
147         }
148         return MessageFormat.format(
149             this.getNamespacePattern(),
150                 StringUtils.trimToEmpty(packageName));
151     }
152 
153     /**
154      * The property defining the default style to give the web services.
155      */
156     private static final String PROPERTY_DEFAULT_STYLE = "defaultStyle";
157 
158     /**
159      * @return UMLProfile.TAGGEDVALUE_WEBSERVICE_STYLE or this.getConfiguredProperty(PROPERTY_DEFAULT_STYLE)
160      * @see org.andromda.cartridges.webservice.metafacades.WebService#getStyle()
161      */
162     protected String handleGetStyle()
163     {
164         String style = (String)this.findTaggedValue(UMLProfile.TAGGEDVALUE_WEBSERVICE_STYLE);
165         if (StringUtils.isBlank(style) || style.equals(DEFAULT))
166         {
167             style = String.valueOf(this.getConfiguredProperty(PROPERTY_DEFAULT_STYLE));
168         }
169         return style;
170     }
171 
172     /**
173      * The property defining the default style to give the web services.
174      */
175     private static final String PROPERTY_DEFAULT_USE = "defaultUse";
176 
177     /**
178      * @return UMLProfile.TAGGEDVALUE_WEBSERVICE_USE or this.getConfiguredProperty(PROPERTY_DEFAULT_USE
179      * @see org.andromda.cartridges.webservice.metafacades.WebService#getUse()
180      */
181     protected String handleGetUse()
182     {
183         String use = (String)this.findTaggedValue(UMLProfile.TAGGEDVALUE_WEBSERVICE_USE);
184         if (StringUtils.isBlank(use) || use.equals(DEFAULT))
185         {
186             use = String.valueOf(this.getConfiguredProperty(PROPERTY_DEFAULT_USE));
187         }
188         return use;
189     }
190 
191     /**
192      * Sorted list of all type mapping elements (package.class), used to iterate through all elements in a service
193      */
194     private Set<ModelElementFacade> elementSet = new TreeSet<ModelElementFacade>(new TypeComparator());
195 
196     /**
197      * Keeps track of whether or not the type has been checked, keeps us from entering infinite loops when calling
198      * loadTypes.
199      */
200     private Collection<ModelElementFacade> checkedTypes = new ArrayList<ModelElementFacade>();
201 
202     /**
203      * @return this.elementSet types
204      * @see org.andromda.cartridges.webservice.metafacades.WebService#getTypeMappingElements()
205      */
206     protected Collection<ModelElementFacade> handleGetTypeMappingElements()
207     {
208         final Collection<ParameterFacade> parameterTypes = new LinkedHashSet<ParameterFacade>();
209         for (final WebServiceOperation operation : this.getAllowedOperations())
210         {
211             parameterTypes.addAll(operation.getParameters());
212         }
213 
214         final Set<ModelElementFacade> types = new TreeSet<ModelElementFacade>(new TypeComparator());
215         final Collection<ModelElementFacade> nonArrayTypes = new TreeSet<ModelElementFacade>(new TypeComparator());
216 
217         // clear out the cache of checkedTypes, otherwise
218         // they'll be ignored the second time this method is
219         // called (if the instance is reused)
220         this.checkedTypes.clear();
221         for (final ParameterFacade parameter : parameterTypes)
222         {
223             this.loadTypes((ModelElementFacade)parameter, types, nonArrayTypes);
224         }
225 
226         for (final WebServiceOperation operation : this.getAllowedOperations())
227         {
228             final Collection<ModelElementFacade> exceptions = operation.getExceptions();
229             exceptions.addAll(exceptions);
230             // Exceptions may have attributes too
231             for (final ModelElementFacade exception : exceptions)
232             {
233                 this.loadTypes(exception, types, nonArrayTypes);
234             }
235         }
236 
237         // now since we're at the end, and we know the
238         // non array types won't override any other types
239         // (such as association ends) we
240         // add the non array types to the types
241         types.addAll(nonArrayTypes);
242 
243         this.elementSet = types;
244         //setPkgAbbr(types);
245         return types;
246     }
247 
248     /**
249      * <p> Loads all <code>types</code> and <code>nonArrayTypes</code> for
250      * the specified <code>type</code>. For each array type we collect the
251      * <code>nonArrayType</code>. Non array types are loaded separately so
252      * that they are added at the end at the type collecting process. Since the
253      * types collection is a set (by the fullyQualifiedName) we don't want any
254      * non array types to override things such as association ends in the
255      * <code>types</code> collection.
256      * </p>
257      *
258      * @param type the type
259      * @param types the collection to load.
260      * @param nonArrayTypes the collection of non array types.
261      */
262     private void loadTypes(ModelElementFacade modelElement, Set<ModelElementFacade> types,
263         Collection<ModelElementFacade> nonArrayTypes)
264     {
265         ExceptionUtils.checkNull("types", types);
266         ExceptionUtils.checkNull("nonArrayTypes", nonArrayTypes);
267 
268         try
269         {
270             if (modelElement != null && !this.checkedTypes.contains(modelElement))
271             {
272                 final ClassifierFacade parameterType = this.getType(modelElement);
273 
274                 // only continue if the model element has a type
275                 if (parameterType != null)
276                 {
277                     final Set<ModelElementFacade> allTypes = new LinkedHashSet<ModelElementFacade>();
278                     allTypes.add(parameterType);
279 
280                     // add all generalizations and specializations of the type
281                     final Collection<GeneralizableElementFacade> generalizations = parameterType.getAllGeneralizations();
282 
283                     if (generalizations != null)
284                     {
285                         allTypes.addAll(generalizations);
286                     }
287 
288                     final Collection<GeneralizableElementFacade> specializations = parameterType.getAllSpecializations();
289 
290                     if (specializations != null)
291                     {
292                         allTypes.addAll(specializations);
293                     }
294 
295                     if (!this.checkedTypes.contains(parameterType))
296                     {
297                         this.checkedTypes.add(parameterType);
298 
299                         for (final Iterator allTypesIterator = allTypes.iterator(); allTypesIterator.hasNext();)
300                         {
301                             ClassifierFacade type = (ClassifierFacade) allTypesIterator.next();
302 
303                             if (!this.containsManyType(types, modelElement))
304                             {
305                                 ClassifierFacade nonArrayType = type;
306                                 final boolean arrayType = type.isArrayType();
307 
308                                 if (arrayType || this.isValidAssociationEnd(modelElement))
309                                 {
310                                     types.add(modelElement);
311 
312                                     if (arrayType)
313                                     {
314                                         // convert to non-array type since we
315                                         // check if that one has the stereotype
316                                         nonArrayType = type.getNonArray();
317 
318                                         // set the type to the non array type since
319                                         // that will have the attributes
320                                         type = nonArrayType;
321                                     }
322                                 }
323 
324                                 if (nonArrayType != null)
325                                 {
326                                     if (nonArrayType.hasStereotype(UMLProfile.STEREOTYPE_VALUE_OBJECT)
327                                        || nonArrayType.hasStereotype(UMLProfile.STEREOTYPE_APPLICATION_EXCEPTION)
328                                        || nonArrayType.isEnumeration())
329                                     {
330                                         // we add the type when it's a non array and
331                                         // has the correct stereotype (even if we have
332                                         // added the array type above) since we need to
333                                         // define both an array and non array in the WSDL
334                                         // if we are defining an array.
335                                         nonArrayTypes.add(nonArrayType);
336                                     }
337                                 }
338                             }
339 
340                             if (type != null)
341                             {
342                                 final List<? extends ModelElementFacade> properties = type.getProperties();
343                                 if (properties != null && !properties.isEmpty())
344                                 {
345                                     for (final ModelElementFacade property : properties)
346                                     {
347                                         // Avoid StackOverflowError loading self-referenced types
348                                         if (!property.getFullyQualifiedName().equals(modelElement.getFullyQualifiedName()))
349                                         {
350                                             this.loadTypes(property, types, nonArrayTypes);
351                                         }
352                                     }
353                                 }
354                             }
355                         }
356                     }
357                 }
358             }
359         }
360         catch (final Throwable throwable)
361         {
362             final String message = "Error performing loadTypes";
363             logger.error(throwable);
364             throw new MetafacadeException(message, throwable);
365         }
366     }
367 
368     /**
369      * Cross reference between package name and namespace abbreviation, used to annotate foreign schema elements
370      */
371     private Map<String, String> packageAbbr = new TreeMap<String, String>();
372     private static final String EMPTY_STRING = "";
373 
374     /**
375      * Get a unique list of packages populated from the results of GetTypeMappingElements
376      * @return pkgAbbr TreeSet containing unique package list
377      */
378     protected Collection<String> handleGetPackages()
379     {
380         if (this.elementSet == null || this.elementSet.size()<1)
381         {
382             this.elementSet = (TreeSet<ModelElementFacade>)handleGetTypeMappingElements();
383         }
384         setPkgAbbr(this.elementSet);
385         @SuppressWarnings("unused")
386         String pkgList = EMPTY_STRING;
387         for (final String pkg : this.packageAbbr.keySet())
388         {
389             pkgList += pkg + ", ";
390         }
391         return this.packageAbbr.keySet();
392     }
393 
394     /**
395      * @param pkgName
396      * @return this.packageAbbr.get(pkgName)
397      */
398     protected String handleGetPkgAbbr(String pkgName)
399     {
400         if (StringUtils.isBlank(pkgName) || pkgName.length()<1)
401         {
402             return EMPTY_STRING;
403         }
404         if (this.elementSet == null || this.elementSet.size()<1)
405         {
406             this.elementSet = (TreeSet<ModelElementFacade>)handleGetTypeMappingElements();
407         }
408         if (this.packageAbbr == null || this.packageAbbr.size()<1)
409         {
410             setPkgAbbr(this.elementSet);
411         }
412         String rtn = this.packageAbbr.get(pkgName);
413         if (StringUtils.isBlank(rtn))
414         {
415             // Package reference was never added originally - needs to be fixed
416             int namespaceCount = this.packageAbbr.size();
417             rtn = "ns" + namespaceCount;
418             this.packageAbbr.put(pkgName, rtn);
419             logger.info(this.getName() + " missing PkgAbbr for " + pkgName);
420         }
421         return rtn;
422     }
423 
424     /**
425      * Creates a list of sorted unique package names and namespace abbreviations for each one.
426      * Run this after running getTypeMappingElements(), to populate the namespace Map.
427      * Namespaces are in order ns1 through x
428      * @param types
429      * @return pkgAbbr
430      */
431     private Map<String, String> setPkgAbbr(Set<ModelElementFacade> types)
432     {
433         Map<String, String> pkgAbbr = new TreeMap<String, String>();
434         int namespaceCount = 1;
435         // Copy package names and abbreviations to package list
436         for (final OperationFacade op : this.getOperations())
437         {
438             for (final Iterator opiterator = op.getExceptions().iterator(); opiterator.hasNext();)
439             {
440                 ModelElementFacade arg = (ModelElementFacade)opiterator.next();
441                 String pkg = arg.getPackageName();
442                 if (!pkgAbbr.containsKey(pkg) && pkg != null && pkg.indexOf('.') > 0)
443                 {
444                     pkgAbbr.put(pkg, "ns" + namespaceCount);
445                     namespaceCount++;
446                 }
447             }
448             for (final ParameterFacade arg : op.getArguments())
449             {
450                 String pkg = arg.getPackageName();
451                 if (!pkgAbbr.containsKey(pkg) && pkg != null && pkg.indexOf('.') > 0)
452                 {
453                     pkgAbbr.put(pkg, "ns" + namespaceCount);
454                     namespaceCount++;
455                 }
456             }
457             if (op.getReturnType()!=null)
458             {
459                 String pkg = op.getReturnType().getPackageName();
460                 if (!pkgAbbr.containsKey(pkg) && pkg != null && pkg.indexOf('.') > 0)
461                 {
462                     pkgAbbr.put(pkg, "ns" + namespaceCount);
463                     namespaceCount++;
464                 }
465             }
466         }
467         for (final Iterator iterator = types.iterator(); iterator.hasNext();)
468         {
469             ModelElementFacade type = ((ModelElementFacade)iterator.next());
470             String pkg = type.getPackageName();
471             if (!pkgAbbr.containsKey(pkg) && pkg != null && pkg.indexOf('.') > 0)
472             {
473                 pkgAbbr.put(pkg, "ns" + namespaceCount);
474                 namespaceCount++;
475             }
476         }
477         this.packageAbbr = pkgAbbr;
478         return pkgAbbr;
479     }
480 
481     /**
482      * Cross reference between package name and collection of foreign package referenced elements
483      */
484     private Map<String, Set<String>> packageRefs = new HashMap<String, Set<String>>();
485 
486     /**
487      * Get a unique list of packages referenced by the referring package
488      * @param pkg PackageName to find related packages for xs:schema import
489      * @param follow Follow Inheritance references $extensionInheritanceDisabled
490      * @return Collection TreeSet containing referenced package list
491      */
492     protected Collection<String> handleGetPackageReferences(String pkg, boolean follow)
493     {
494         //if (this.elementSet == null || this.elementSet.size()<1)
495         //{
496             this.elementSet = (TreeSet<ModelElementFacade>)handleGetTypeMappingElements();
497         //}
498         //if (this.packageRefs == null || this.packageRefs.size()<1)
499         //{
500             setPkgRefs(this.elementSet, follow);
501         //}
502         return this.packageRefs.get(pkg);
503     }
504 
505     /**
506      * Creates a list of referenced packages for each package.
507      * Run this after running getTypeMappingElements(), to populate the namespace Map.
508      * @param types TreeSet of unique packageNames referenced in each package
509      * @param follow Follow Inheritance references $extensionInheritanceDisabled
510      * @return pkgAbbr
511      */
512     private Map<String, Set<String>> setPkgRefs(Set<ModelElementFacade> types, boolean follow)
513     {
514         // Copy package names and collection of related packages to package references list
515         // Iterate through previously collected type references to find all packages referenced by each type
516         for (final Iterator<ModelElementFacade> iterator = types.iterator(); iterator.hasNext();)
517         {
518             try
519             {
520                 MetafacadeBase element = (MetafacadeBase)iterator.next();
521                 if (element instanceof WSDLTypeLogicImpl)
522                 {
523                     WSDLTypeLogicImpl type = (WSDLTypeLogicImpl)element;
524                     String pkg = type.getPackageName();
525                     if (pkg != null && pkg.indexOf('.') > 0)
526                     {
527                         // Duplicates logic in wsdl.vsl so that referenced packages are the same.
528                         for (final Iterator<AttributeFacade> itAttr = type.getAttributes(follow).iterator(); itAttr.hasNext();)
529                         {
530                             try
531                             {
532                                 ModelElementFacade attr = (itAttr.next());
533                                 if (getType(attr) != null)
534                                 {
535                                     attr = getType(attr);
536                                 }
537                                 addPkgRef(pkg, attr.getPackageName(), attr);
538                             }
539                             catch (Exception e)
540                             {
541                                 logger.error("WebServiceLogicImpl.setPkgRefs getAttributes: " + e);
542                             }
543                         }
544                     }
545                 }
546                 else if (element instanceof WSDLTypeAssociationEndLogicImpl)
547                 {
548                     WSDLTypeAssociationEndLogicImpl type = (WSDLTypeAssociationEndLogicImpl)element;
549                     String pkg = type.getPackageName();
550                     if (pkg != null && pkg.indexOf('.') > 0)
551                     {
552                         // Duplicates logic in wsdl.vsl so that referenced packages are the same.
553                         for (final Iterator<AssociationEndFacade> otherEnds = type.getType().getNavigableConnectingEnds(follow).iterator(); otherEnds.hasNext();)
554                         {
555                             try
556                             {
557                                 ModelElementFacade otherEnd = ((ModelElementFacade)otherEnds.next());
558                                 if (getType(otherEnd) != null)
559                                 {
560                                     otherEnd = getType(otherEnd);
561                                 }
562                                 addPkgRef(pkg, otherEnd.getPackageName(), otherEnd);
563                             }
564                             catch (RuntimeException e)
565                             {
566                                 logger.error("WebServiceLogicImpl.setPkgRefs getNavigableConnectingEnds: " + e);
567                             }
568                         }
569                     }
570                 }
571                 else
572                 {
573                     // Log the type so we can extend this logic later...
574                     logger.error("Unexpected element type: " + element);
575                 }
576             }
577             catch (Exception e)
578             {
579                 logger.error("WebServiceLogicImpl.setPkgRefs types: " + e);
580             }
581         }
582         // Copy package names and collection of related packages to package references list
583         /* for (final Iterator iterator = types.iterator(); iterator.hasNext();)
584         {
585             TreeSet pkgRef;
586             ClassifierFacade element = ((ClassifierFacade)iterator.next());
587             String pkg = element.getPackageName();
588             if (!packageRefs.containsKey(pkg))
589             {
590                 // TypeComparator disallows adding nonunique referenced packageNames
591                 pkgRef = new TreeSet(new TypeComparator());
592             }
593             else
594             {
595                 // Reference to Set contained in pkgAbbr already, can be changed dynamically
596                 pkgRef = (TreeSet)packageRefs.get(pkg);
597             }
598             // Duplicates logic in wsdl.vsl so that referenced packages are the same.
599             for (final Iterator itAttr = element.getAttributes(follow).iterator(); itAttr.hasNext();)
600             {
601                 ClassifierFacade attr = ((ClassifierFacade)itAttr.next());
602                 if (getType(attr) != null)
603                 {
604                     attr = getType(attr);
605                 }
606                 if (!pkgRef.contains(attr) && attr != null && attr.getPackageName().length() > 0)
607                 {
608                     pkgRef.add(attr.getPackageName());
609                 }
610             }
611             for (final Iterator otherEnds = element.getNavigableConnectingEnds(follow).iterator(); otherEnds.hasNext();)
612             {
613                 ClassifierFacade otherEnd = ((ClassifierFacade)otherEnds.next());
614                 if (getType(otherEnd) != null)
615                 {
616                     otherEnd = getType(otherEnd);
617                 }
618                 if (!pkgRef.contains(otherEnd))
619                 {
620                     pkgRef.add(otherEnd.getPackageName());
621                 }
622             }
623             if (!packageRefs.containsKey(pkg))
624             {
625                 packageRefs.put(pkg, pkgRef);
626             }
627         } */
628 
629         // Add references from the operations of the service package itself
630         for (final OperationFacade op : this.getOperations())
631         {
632             for (final Object exception : op.getExceptions())
633             {
634                 ModelElementFacade arg = (ModelElementFacade)exception;
635                 addPkgRef(this.getPackageName(), arg.getPackageName(), arg);
636             }
637             for (final ParameterFacade arg : op.getArguments())
638             {
639                 addPkgRef(this.getPackageName(), arg.getPackageName(), arg);
640             }
641             if (op.getReturnType()!=null)
642             {
643                 String pkg = op.getReturnType().getPackageName();
644                 addPkgRef(this.getPackageName(), pkg, op.getReturnType());
645             }
646         }
647         return packageRefs;
648     }
649 
650     private void addPkgRef(String pkg, String pkgRef, ModelElementFacade type)
651     {
652         Set<String> pkgRefSet;
653         if (!packageRefs.containsKey(pkg))
654         {
655             // TypeComparator disallows adding nonunique referenced packageNames
656             pkgRefSet = new TreeSet<String>();
657             packageRefs.put(pkg, pkgRefSet);
658         }
659         else
660         {
661             // Reference to Set contained in pkgAbbr already, can be changed dynamically
662             pkgRefSet = packageRefs.get(pkg);
663         }
664         if (pkgRef!=null && pkg!=null &&  !pkgRef.equals(pkg) && pkgRef.indexOf('.') > 0 && !pkgRefSet.contains(pkgRef))
665         {
666             pkgRefSet.add(pkgRef);
667             logger.debug("Added pkgRef " + pkg + " references " + pkgRef + " in " + type.getName());
668         }
669     }
670 
671     /**
672      * <p> Checks to see if the <code>types</code> collection contains the
673      * <code>modelElement</code>. It does this by checking to see if the
674      * model element is either an association end or some type of model element
675      * that has a type that's an array. If it's either an array <strong>OR
676      * </strong> an association end, then we check to see if the type is stored
677      * within the <code>types</code> collection. If so, we return true,
678      * otherwise we return false.
679      * </p>
680      *
681      * @param types the previously collected types.
682      * @param modelElement the model element to check to see if it represents a
683      *        <code>many</code> type
684      * @return true/false depending on whether or not the model element is a
685      *         many type.
686      */
687     private boolean containsManyType(
688         final Collection<ModelElementFacade> types,
689         final Object modelElement)
690     {
691         final ClassifierFacade compareType = this.getClassifier(modelElement);
692         boolean containsManyType = false;
693         if (compareType != null)
694         {
695             containsManyType =
696                 CollectionUtils.find(
697                     types,
698                     new Predicate()
699                     {
700                         public boolean evaluate(Object object)
701                         {
702                             return compareType.equals(getClassifier(object));
703                         }
704                     }) != null;
705         }
706         return containsManyType;
707     }
708 
709     /**
710      * Attempts to get the classifier attached to the given <code>element</code>.
711      *
712      * @param element the element from which to retrieve the classifier.
713      * @return the classifier if found, null otherwise
714      */
715     private ClassifierFacade getClassifier(final Object element)
716     {
717         ClassifierFacade type = null;
718         if (element instanceof AssociationEndFacade)
719         {
720             AssociationEndFacade end = (AssociationEndFacade)element;
721             if (end.isMany())
722             {
723                 type = ((AssociationEndFacade)element).getType();
724             }
725         }
726         else if (element instanceof AttributeFacade)
727         {
728             type = ((AttributeFacade)element).getType();
729         }
730         else if (element instanceof ParameterFacade)
731         {
732             type = ((ParameterFacade)element).getType();
733         }
734         if (element instanceof ClassifierFacade)
735         {
736             type = (ClassifierFacade)element;
737         }
738         if (type != null)
739         {
740             if (type.isArrayType())
741             {
742                 type = type.getNonArray();
743             }
744         }
745         return type;
746     }
747 
748     /**
749      * Returns true/false depending on whether or not this class represents a valid association end (meaning it has a
750      * multiplicity of many)
751      *
752      * @param modelElement the model element to check.
753      * @return true/false
754      */
755     private boolean isValidAssociationEnd(Object modelElement)
756     {
757         return modelElement instanceof AssociationEndFacade && ((AssociationEndFacade)modelElement).isMany();
758     }
759 
760     /**
761      * @return this.getConfiguredProperty("defaultProvider")
762      * @see org.andromda.cartridges.webservice.metafacades.WebService#getProvider()
763      */
764     protected String handleGetProvider()
765     {
766         String provider = (String)this.findTaggedValue(UMLProfile.TAGGEDVALUE_WEBSERVICE_PROVIDER);
767         if (StringUtils.isBlank(provider) || provider.equals(DEFAULT))
768         {
769             provider = (String)this.getConfiguredProperty("defaultProvider");
770         }
771         return provider;
772     }
773 
774     /**
775      * @return this.getConfiguredProperty(UMLMetafacadeProperties.NAMESPACE_SEPARATOR)
776      * @see org.andromda.cartridges.webservice.metafacades.WebService#getWsdlFile()
777      */
778     protected String handleGetWsdlFile()
779     {
780         return StringUtils.replace(
781             this.getFullyQualifiedName(),
782             String.valueOf(this.getConfiguredProperty(UMLMetafacadeProperties.NAMESPACE_SEPARATOR)),
783             "/") + ".wsdl";
784     }
785 
786     /**
787      * We use this comparator to actually eliminate duplicates instead of sorting like a comparator is normally used.
788      */
789     public final class TypeComparator
790         implements Comparator
791     {
792         private final Collator collator = Collator.getInstance();
793 
794         /**
795          * We use this comparator to actually eliminate duplicates instead of sorting like a comparator is normally used.
796          */
797         public TypeComparator()
798         {
799             collator.setStrength(Collator.PRIMARY);
800         }
801 
802         /**
803          * @see java.util.Comparator#compare(Object, Object)
804          */
805         public int compare(
806             Object objectA,
807             Object objectB)
808         {
809             final ModelElementFacade a = (ModelElementFacade)objectA;
810             ModelElementFacade aType = getType(a);
811             if (aType == null)
812             {
813                 aType = a;
814             }
815             final ModelElementFacade b = (ModelElementFacade)objectB;
816             ModelElementFacade bType = getType(b);
817             if (bType == null)
818             {
819                 bType = b;
820             }
821             return collator.compare(
822                 aType.getFullyQualifiedName(),
823                 bType.getFullyQualifiedName());
824         }
825     }
826 
827     /**
828      * Gets the <code>type</code> or <code>returnType</code> of the model element (if the model element has a type or
829      * returnType).
830      *
831      * @param modelElement the model element we'll retrieve the type of.
832      * @return ClassifierFacade Type of modelElement Object
833      */
834     public ClassifierFacade getType(Object modelElement)
835     {
836         try
837         {
838             final Introspector introspector = Introspector.instance();
839             ClassifierFacade type = null;
840             String typeProperty = "type";
841 
842             // only continue if the model element has a type
843             if (introspector.isReadable(modelElement, typeProperty))
844             {
845                 type = (ClassifierFacade)introspector.getProperty(modelElement, typeProperty);
846             }
847 
848             // try for return type if type wasn't found
849             typeProperty = "returnType";
850             if (type == null && introspector.isReadable(modelElement, typeProperty))
851             {
852                 type = (ClassifierFacade)introspector.getProperty(modelElement, typeProperty);
853             }
854             // Sometimes the type is sent to this method instead of the property
855             if (type == null && modelElement instanceof ClassifierFacade)
856             {
857                 type = (ClassifierFacade)modelElement;
858             }
859             return type;
860         }
861         catch (final Throwable throwable)
862         {
863             String errMsg = "Error performing WebServiceLogicImpl.getType";
864             logger.error(errMsg, throwable);
865             throw new MetafacadeException(errMsg, throwable);
866         }
867     }
868 
869     /**
870      * namespacePrefix
871      */
872     static final String NAMESPACE_PREFIX = "namespacePrefix";
873 
874     /**
875      * @return this.getConfiguredProperty(NAMESPACE_PREFIX)
876      * @see org.andromda.cartridges.webservice.metafacades.WSDLType#getNamespacePrefix()
877      */
878     protected String handleGetNamespacePrefix()
879     {
880         String prefix = (String)this.getConfiguredProperty(NAMESPACE_PREFIX);
881         if (StringUtils.isBlank(prefix))
882         {
883             prefix = "impl";
884         }
885         return prefix;
886     }
887 
888     /**
889      * qualifiedNameLocalPartPattern
890      */
891     static final String QNAME_LOCAL_PART_PATTERN = "qualifiedNameLocalPartPattern";
892 
893     /**
894      * Gets the <code>qualifiedNameLocalPartPattern</code> for this service.
895      * @return this.getConfiguredProperty(QNAME_LOCAL_PART_PATTERN)
896      */
897     protected String getQualifiedNameLocalPartPattern()
898     {
899         String pattern = (String)this.getConfiguredProperty(QNAME_LOCAL_PART_PATTERN);
900         if (StringUtils.isBlank(pattern))
901         {
902             pattern = "{0}";
903         }
904         return pattern;
905     }
906 
907     /**
908      * namespacePattern
909      */
910     static final String NAMESPACE_PATTERN = "namespacePattern";
911 
912     /**
913      * Gets the <code>namespacePattern</code> for this service.
914      *
915      * @return String the namespace pattern to use.
916      */
917     protected String getNamespacePattern()
918     {
919         String pattern = (String)this.getConfiguredProperty(NAMESPACE_PATTERN);
920         if (StringUtils.isBlank(pattern))
921         {
922             pattern = "http://{0}/";
923         }
924         return pattern;
925     }
926 
927     /**
928      * reverseNamespace
929      */
930     static final String REVERSE_NAMESPACE = "reverseNamespace";
931 
932     /**
933      * Gets whether or not <code>reverseNamespace</code> is true/false for this type.
934      *
935      * @return boolean true/false
936      */
937     protected boolean isReverseNamespace()
938     {
939         return Boolean.valueOf(String.valueOf(this.getConfiguredProperty(REVERSE_NAMESPACE))).booleanValue();
940     }
941 
942     /**
943      * @return this.getEjbJndiNamePrefix() + ejb/ + this.getFullyQualifiedName()
944      * @see org.andromda.cartridges.webservice.metafacades.WebService#getEjbJndiName()
945      */
946     protected String handleGetEjbJndiName()
947     {
948         StringBuilder jndiName = new StringBuilder();
949         String jndiNamePrefix = StringUtils.trimToEmpty(this.getEjbJndiNamePrefix());
950         if (StringUtils.isNotBlank(jndiNamePrefix))
951         {
952             jndiName.append(jndiNamePrefix);
953             jndiName.append('/');
954         }
955         jndiName.append("ejb/");
956         jndiName.append(this.getFullyQualifiedName());
957         return jndiName.toString();
958     }
959 
960     /**
961      * Gets the <code>ejbJndiNamePrefix</code> for an EJB provider.
962      *
963      * @return the EJB Jndi name prefix.
964      */
965     protected String getEjbJndiNamePrefix()
966     {
967         final String property = "ejbJndiNamePrefix";
968         return this.isConfiguredProperty(property) ? ObjectUtils.toString(this.getConfiguredProperty(property)) : null;
969     }
970 
971     /**
972      * @return this.getEjbHomeInterfacePattern() formatted as this.getPackageName() + this.getName()
973      * @see org.andromda.cartridges.webservice.metafacades.WebService#getEjbHomeInterface()
974      */
975     protected String handleGetEjbHomeInterface()
976     {
977         return MessageFormat.format(
978             this.getEjbHomeInterfacePattern(),
979                 StringUtils.trimToEmpty(this.getPackageName()), StringUtils.trimToEmpty(this.getName()));
980     }
981 
982     /**
983      * Gets the <code>ejbHomeInterfacePattern</code> for an EJB provider.
984      *
985      * @return the EJB Home interface pattern
986      */
987     protected String getEjbHomeInterfacePattern()
988     {
989         return (String)this.getConfiguredProperty("ejbHomeInterfacePattern");
990     }
991 
992     /**
993      * @return this.getEjbInterfacePattern() formatted as this.getPackageName() + this.getName()
994      * @see org.andromda.cartridges.webservice.metafacades.WebService#getEjbInterface()
995      */
996     protected String handleGetEjbInterface()
997     {
998         return MessageFormat.format(
999             this.getEjbInterfacePattern(),
1000                 StringUtils.trimToEmpty(this.getPackageName()), StringUtils.trimToEmpty(this.getName()));
1001     }
1002 
1003     /**
1004      * Gets the <code>ejbInterfacePattern</code> for an EJB provider.
1005      *
1006      * @return the EJB interface pattern
1007      */
1008     protected String getEjbInterfacePattern()
1009     {
1010         return (String)this.getConfiguredProperty("ejbInterfacePattern");
1011     }
1012 
1013     private static final String RPC_CLASS_NAME_PATTERN = "rpcClassNamePattern";
1014 
1015     /**
1016      * Gets the <code>rpcClassNamePattern</code> for this service.
1017      * @return this.getConfiguredProperty(RPC_CLASS_NAME_PATTERN)
1018      */
1019     protected String getRpcClassNamePattern()
1020     {
1021         return (String)this.getConfiguredProperty(RPC_CLASS_NAME_PATTERN);
1022     }
1023 
1024     /**
1025      * @return this.getRpcClassNamePattern() formatted as this.getPackageName() + this.getName()
1026      * @see org.andromda.cartridges.webservice.metafacades.WebService#getRpcClassName()
1027      */
1028     protected String handleGetRpcClassName()
1029     {
1030         return MessageFormat.format(
1031             this.getRpcClassNamePattern(),
1032                 StringUtils.trimToEmpty(this.getPackageName()), StringUtils.trimToEmpty(this.getName()));
1033     }
1034 
1035     private static final String WSDL_OPERATION_SORT_MODE = "wsdlOperationSortMode";
1036 
1037     /**
1038      * Used to sort operations by <code>name</code>.
1039      */
1040     public static final class OperationNameComparator
1041         implements Comparator
1042     {
1043         private final Collator collator = Collator.getInstance();
1044 
1045         /**
1046          *
1047          */
1048         public OperationNameComparator()
1049         {
1050             collator.setStrength(Collator.PRIMARY);
1051         }
1052 
1053         /**
1054          * @see java.util.Comparator#compare(Object, Object)
1055          */
1056         public int compare(
1057             Object objectA,
1058             Object objectB)
1059         {
1060             ModelElementFacade a = (ModelElementFacade)objectA;
1061             ModelElementFacade b = (ModelElementFacade)objectB;
1062 
1063             return collator.compare(
1064                 a.getName(),
1065                 b.getName());
1066         }
1067     }
1068 
1069     /**
1070      * The model specifying operations should be sorted by name.
1071      */
1072     private static final String OPERATION_SORT_MODE_NAME = "name";
1073 
1074     /**
1075      * The model specifying operations should NOT be sorted.
1076      */
1077     private static final String OPERATION_SORT_MODE_NONE = "none";
1078 
1079     /**
1080      * Gets the sort mode WSDL operations.
1081      *
1082      * @return String
1083      */
1084     private String getWSDLOperationSortMode()
1085     {
1086         Object property = this.getConfiguredProperty(WSDL_OPERATION_SORT_MODE);
1087         return property != null ? (property.equals(OPERATION_SORT_MODE_NAME) ? (String)property : OPERATION_SORT_MODE_NONE) : OPERATION_SORT_MODE_NONE;
1088     }
1089 
1090     /**
1091      * @return !this.getAllRoles().isEmpty()
1092      * @see org.andromda.cartridges.webservice.metafacades.WebService#isSecured()
1093      */
1094     protected boolean handleIsSecured()
1095     {
1096         Collection<Role> roles = this.getAllRoles();
1097         return roles != null && !roles.isEmpty();
1098     }
1099 
1100     /**
1101      * Overridden to only allow the exposed operations in the returned roles collection.
1102      *
1103      * @see org.andromda.metafacades.uml.Service#getAllRoles()
1104      */
1105     public Collection<Role> getAllRoles()
1106     {
1107         final Collection<Role> roles = new LinkedHashSet<Role>(this.getRoles());
1108         CollectionUtils.forAllDo(
1109             this.getAllowedOperations(),
1110             new Closure()
1111             {
1112                 public void execute(Object object)
1113                 {
1114                     if (object != null && ServiceOperation.class.isAssignableFrom(object.getClass()))
1115                     {
1116                         roles.addAll(((ServiceOperation)object).getRoles());
1117                     }
1118                 }
1119             });
1120         return roles;
1121     }
1122 
1123     /**
1124      * The pattern used to construct the test package name.
1125      */
1126     private static final String TEST_PACKAGE_NAME_PATTERN = "testPackageNamePattern";
1127 
1128     /**
1129      * @return this.getPackageName() formatted as this.getConfiguredProperty(TEST_PACKAGE_NAME_PATTERN)
1130      * @see org.andromda.cartridges.webservice.metafacades.WebService#getTestPackageName()
1131      */
1132     protected String handleGetTestPackageName()
1133     {
1134         return String.valueOf(this.getConfiguredProperty(TEST_PACKAGE_NAME_PATTERN)).replaceAll(
1135             "\\{0\\}",
1136             this.getPackageName());
1137     }
1138 
1139     /**
1140      * @return this.getTestPackageName() + '.' + this.getTestName()
1141      * @see org.andromda.cartridges.webservice.metafacades.WebService#getFullyQualifiedTestName()
1142      */
1143     protected String handleGetFullyQualifiedTestName()
1144     {
1145         return this.getTestPackageName() + '.' + this.getTestName();
1146     }
1147 
1148     /**
1149      * The pattern used to construct the test name.
1150      */
1151     private static final String TEST_NAME_PATTERN = "testNamePattern";
1152 
1153     /**
1154      * @return this.getName() formatted with this.getConfiguredProperty(TEST_NAME_PATTERN)
1155      * @see org.andromda.cartridges.webservice.metafacades.WebService#getTestName()
1156      */
1157     protected String handleGetTestName()
1158     {
1159         return String.valueOf(this.getConfiguredProperty(TEST_NAME_PATTERN)).replaceAll(
1160             "\\{0\\}",
1161             this.getName());
1162     }
1163 
1164     /**
1165      * Represents a "wrapped" style.
1166      */
1167     private static final String STYLE_WRAPPED = "wrapped";
1168 
1169     /**
1170      * @return this.getStyle().equalsIgnoreCase(STYLE_WRAPPED)
1171      * @see org.andromda.cartridges.webservice.metafacades.WebService#isWrappedStyle()
1172      */
1173     protected boolean handleIsWrappedStyle()
1174     {
1175         return this.getStyle().equalsIgnoreCase(STYLE_WRAPPED);
1176     }
1177 
1178     /**
1179      * Represents a "document" style.
1180      */
1181     private static final String STYLE_DOCUMENT = "document";
1182 
1183     /**
1184      * @return this.getStyle().equalsIgnoreCase("document")
1185      * @see org.andromda.cartridges.webservice.metafacades.WebService#isDocumentStyle()
1186      */
1187     protected boolean handleIsDocumentStyle()
1188     {
1189         return this.getStyle().equalsIgnoreCase(STYLE_DOCUMENT);
1190     }
1191 
1192     /**
1193      * Represents a "rpc" style.
1194      */
1195     private static final String STYLE_RPC = "rpc";
1196 
1197     /**
1198      * @return this.getStyle().equalsIgnoreCase("rpc")
1199      * @see org.andromda.cartridges.webservice.metafacades.WebService#isRpcStyle()
1200      */
1201     protected boolean handleIsRpcStyle()
1202     {
1203         return this.getStyle().equalsIgnoreCase(STYLE_RPC);
1204     }
1205 
1206     /**
1207      * Represents an "literal" use.
1208      */
1209     private static final String USE_LITERAL = "literal";
1210 
1211     /**
1212      * @return this.getStyle().equalsIgnoreCase("literal")
1213      * @see org.andromda.cartridges.webservice.metafacades.WebService#isLiteralUse()
1214      */
1215     protected boolean handleIsLiteralUse()
1216     {
1217         return this.getStyle().equalsIgnoreCase(USE_LITERAL);
1218     }
1219 
1220     /**
1221      * Represents an "encoded" use.
1222      */
1223     private static final String USE_ENCODED = "encoded";
1224 
1225     /**
1226      * @return this.getStyle().equalsIgnoreCase("encoded")
1227      * @see org.andromda.cartridges.webservice.metafacades.WebService#isEncodedUse()
1228      */
1229     protected boolean handleIsEncodedUse()
1230     {
1231         return this.getStyle().equalsIgnoreCase(USE_ENCODED);
1232     }
1233 
1234     /**
1235      * The pattern used to construct the test implementation name.
1236      */
1237     private static final String TEST_IMPLEMENTATION_NAME_PATTERN = "testImplementationNamePattern";
1238 
1239     /**
1240      * @return this.getName() formatted as this.getConfiguredProperty(TEST_IMPLEMENTATION_NAME_PATTERN)
1241      * @see org.andromda.cartridges.webservice.metafacades.WebService#getTestImplementationName()
1242      */
1243     protected String handleGetTestImplementationName()
1244     {
1245         return String.valueOf(this.getConfiguredProperty(TEST_IMPLEMENTATION_NAME_PATTERN)).replaceAll(
1246             "\\{0\\}",
1247             this.getName());
1248     }
1249 
1250     /**
1251      * @return this.getTestPackageName() + '.' + this.getTestImplementationName()
1252      * @see org.andromda.cartridges.webservice.metafacades.WebService#getFullyQualifiedTestImplementationName()
1253      */
1254     protected String handleGetFullyQualifiedTestImplementationName()
1255     {
1256         return this.getTestPackageName() + '.' + this.getTestImplementationName();
1257     }
1258 
1259     /**
1260 
1261      * @return TypeMappings from WebServiceGlobals.SCHEMA_TYPE_MAPPINGS_URI "schemaTypeMappingsUri"
1262      * @see org.andromda.cartridges.webservice.metafacades.WebService#getSchemaMappings()
1263      */
1264     protected TypeMappings handleGetSchemaMappings()
1265     {
1266         final String propertyName = WebServiceGlobals.SCHEMA_TYPE_MAPPINGS_URI;
1267         Object property = this.getConfiguredProperty(propertyName);
1268         TypeMappings mappings = null;
1269         String uri = null;
1270         if (property instanceof String)
1271         {
1272             uri = (String)property;
1273             try
1274             {
1275                 mappings = TypeMappings.getInstance(uri);
1276                 mappings.setArraySuffix(this.getArraySuffix());
1277                 this.setProperty(propertyName, mappings);
1278             }
1279             catch (Throwable th)
1280             {
1281                 String errMsg = "Error getting '" + propertyName + "' --> '" + uri + '\'';
1282                 logger.error(errMsg, th);
1283                 // don't throw the exception
1284             }
1285         }
1286         else
1287         {
1288             mappings = (TypeMappings)property;
1289         }
1290         return mappings;
1291     }
1292 
1293     /**
1294      * Gets the array suffix from the configured metafacade properties.
1295      *
1296      * @return the array suffix.
1297      */
1298     private String getArraySuffix()
1299     {
1300         return String.valueOf(this.getConfiguredProperty(UMLMetafacadeProperties.ARRAY_NAME_SUFFIX));
1301     }
1302 
1303     /**
1304      * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#handleGetAllowedOperationExceptions()
1305      */
1306     protected Collection handleGetAllowedOperationExceptions()
1307     {
1308         final Collection exceptions = new HashSet();
1309 
1310         // collect the exceptions of all allowed operations into a single set
1311         for (final OperationFacade operation : this.getAllowedOperations())
1312         {
1313             exceptions.addAll(operation.getExceptions());
1314         }
1315 
1316         return exceptions;
1317     }
1318 
1319     /**
1320      * @return packages from this.getAllowedOperations()
1321      * @see org.andromda.cartridges.webservice.WebServiceUtils#getPackages(WebServiceLogicImpl, Set, boolean)
1322      */
1323     public Collection<PackageFacade> getPackages() {
1324         return new WebServiceUtils().getPackages(this, (Set) this.getAllowedOperations(), true);
1325     }
1326 
1327     /**
1328      * @param pkg
1329      * @return WebServiceUtils().getPkgAbbr(pkg)
1330      * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogicImpl#getPkgAbbr(PackageFacade)
1331      */
1332     public String getPkgAbbr(PackageFacade pkg) {
1333         return new WebServiceUtils().getPkgAbbr(pkg);
1334     }
1335 
1336     /**
1337      * The property defining if the web service XML should be validated against the wsdl/xsd schema.
1338      */
1339     private static final String PROPERTY_SCHEMA_VALIDATION = "schemaValidation";
1340     private static final String BOOLEAN_FALSE = "false";
1341     private static final String BOOLEAN_TRUE = "true";
1342 
1343     /**
1344      * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#handleIsSchemaValidation()
1345      */
1346     @Override
1347     protected boolean handleIsSchemaValidation()
1348     {
1349         String mode = (String)this.findTaggedValue(WebServiceGlobals.XML_SCHEMA_VALIDATION);
1350         if (StringUtils.isBlank(mode) || mode.equals(DEFAULT))
1351         {
1352             mode = String.valueOf(this.getConfiguredProperty(PROPERTY_SCHEMA_VALIDATION));
1353         }
1354         if (StringUtils.isBlank(mode) || mode.equals(DEFAULT))
1355         {
1356             mode = BOOLEAN_FALSE;
1357         }
1358         return Boolean.parseBoolean(mode);
1359     }
1360 
1361     /**
1362      * The property defining the default style to give the web services.
1363      */
1364     private static final String PROPERTY_SIMPLE_BINDING_MODE = "simpleBindingMode";
1365 
1366     /**
1367      * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#handleIsSimpleBindingMode()
1368      */
1369     @Override
1370     protected boolean handleIsSimpleBindingMode()
1371     {
1372         String mode = (String)this.findTaggedValue(WebServiceGlobals.JAXB_SIMPLE_BINDING_MODE);
1373         if (StringUtils.isBlank(mode) || mode.equals(DEFAULT))
1374         {
1375             mode = String.valueOf(this.getConfiguredProperty(PROPERTY_SIMPLE_BINDING_MODE));
1376         }
1377         return Boolean.parseBoolean(mode);
1378     }
1379 
1380     /**
1381      * The property defining the Jaxb XJC arguments used with wsdl2java utility.
1382      * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#getSchemaMappings()
1383      */
1384     private static final String PROPERTY_XJC_ARGUMENTS = "xjcArguments";
1385 
1386     /**
1387      * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#getXjcArguments()
1388      */
1389     @Override
1390     protected String handleGetXjcArguments()
1391     {
1392         String mode = (String)this.findTaggedValue(WebServiceGlobals.JAXB_XJC_ARGUMENTS);
1393         if (StringUtils.isBlank(mode) || mode.equals(DEFAULT))
1394         {
1395             mode = String.valueOf(this.getConfiguredProperty(PROPERTY_XJC_ARGUMENTS));
1396         }
1397         return mode;
1398     }
1399 
1400     /**
1401      * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#getRestCacheType()
1402      */
1403     @Override
1404     protected String handleGetRestCacheType()
1405     {
1406         String cacheType = (String)this.findTaggedValue(WebServiceGlobals.CACHE_TYPE);
1407         if (!(this.getRestCount()>0) || StringUtils.isBlank(cacheType) || cacheType.equals(DEFAULT))
1408         {
1409             cacheType = EMPTY_STRING;
1410         }
1411         return cacheType;
1412     }
1413 
1414     /**
1415      * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#getRestConsumes()
1416      */
1417     @Override
1418     protected String handleGetRestConsumes()
1419     {
1420         String consumes = (String)this.findTaggedValue(WebServiceGlobals.REST_CONSUMES);
1421         if (!(this.getRestCount()>0) || StringUtils.isBlank(consumes) || consumes.equals(DEFAULT))
1422         {
1423             consumes = EMPTY_STRING;
1424         }
1425         else
1426         {
1427             consumes = WebServiceOperationLogicImpl.translateMediaType(consumes);
1428         }
1429         return consumes;
1430     }
1431 
1432     /**
1433      * Contexts should be in the form fullyqualifiedclassname variable
1434      * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#getRestContexts()
1435      */
1436     @Override
1437     protected List<String> handleGetRestContexts()
1438     {
1439         List<String> contexts = new ArrayList<String>();
1440         String context = (String)this.findTaggedValue(WebServiceGlobals.REST_CONTEXT);
1441         if (!(this.getRestCount()>0) || StringUtils.isBlank(context) || context.equals(DEFAULT))
1442         {
1443             context = EMPTY_STRING;
1444         }
1445         else
1446         {
1447             // Parse comma/pipe/semicolon delimited elements into ArrayList
1448             String[] parsed = StringUtils.split(context, ",;|");
1449             for (int i=0; i<parsed.length; i++)
1450             {
1451                 contexts.add(parsed[i]);
1452             }
1453         }
1454         return contexts;
1455     }
1456 
1457     /**
1458      * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#getRestMethod()
1459      */
1460     @Override
1461     protected String handleGetRestMethod()
1462     {
1463         String method = (String)this.findTaggedValue(WebServiceGlobals.REST_HTTP_METHOD);
1464         if (!(this.getRestCount()>0) || StringUtils.isBlank(method) || method.equals(DEFAULT))
1465         {
1466             method = EMPTY_STRING;
1467         }
1468         return method;
1469     }
1470 
1471     private static final String SLASH = "/";
1472     private static final String QUOTE = "\"";
1473     //private static final String LBRACKET = "{";
1474     //private static final String RBRACKET = "}";
1475     /**
1476      * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#getRestPath()
1477      */
1478     @Override
1479     protected String handleGetRestPath()
1480     {
1481         String path = (String)this.findTaggedValue(WebServiceGlobals.REST_PATH);
1482         if (StringUtils.isBlank(path))
1483         {
1484             path = EMPTY_STRING;
1485         }
1486         if (!(this.getRestCount()>0) || StringUtils.isBlank(path) || path.equals(DEFAULT))
1487         {
1488             path = QUOTE + SLASH + this.getName().toLowerCase() + SLASH + QUOTE;
1489         }
1490         else
1491         {
1492             if (!path.startsWith(QUOTE))
1493             {
1494                 path = QUOTE + path;
1495             }
1496             if (!path.endsWith(QUOTE) || path.length()<2)
1497             {
1498                 path = path + QUOTE;
1499             }
1500         }
1501         return path;
1502     }
1503 
1504     //private static final String PRODUCE_DEFAULT = "application/xml";
1505     /**
1506      * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#getRestProduces()
1507      */
1508     @Override
1509     protected String handleGetRestProduces()
1510     {
1511         return WebServiceOperationLogicImpl.translateMediaType((String)this.findTaggedValue(WebServiceGlobals.REST_PRODUCES));
1512     }
1513 
1514     /**
1515      * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#getRestProvider()
1516      */
1517     @Override
1518     protected String handleGetRestProvider()
1519     {
1520         String provider = (String)this.findTaggedValue(WebServiceGlobals.REST_PROVIDER);
1521         if (!(this.getRestCount()>0) || StringUtils.isBlank(provider) || provider.equals(DEFAULT))
1522         {
1523             provider = EMPTY_STRING;
1524         }
1525         return provider;
1526     }
1527 
1528     /**
1529      * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#getRestRetention()
1530      */
1531     @Override
1532     protected String handleGetRestRetention()
1533     {
1534         String retention = (String)this.findTaggedValue(WebServiceGlobals.REST_RETENTION);
1535         if (!(this.getRestCount()>0) || StringUtils.isBlank(retention) || retention.equals(DEFAULT))
1536         {
1537             retention = EMPTY_STRING;
1538         }
1539         return retention;
1540     }
1541 
1542     /**
1543      * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#getRestTarget()
1544      */
1545     @Override
1546     protected String handleGetRestTarget()
1547     {
1548         String target = (String)this.findTaggedValue(WebServiceGlobals.REST_TARGET);
1549         if (!(this.getRestCount()>0) || StringUtils.isBlank(target) || target.equals(DEFAULT))
1550         {
1551             target = EMPTY_STRING;
1552         }
1553         return target;
1554     }
1555 
1556     /**
1557      * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#handleIsRestAtom()
1558      */
1559     @Override
1560     protected boolean handleIsRestAtom()
1561     {
1562         boolean restAtom = false;
1563         if (this.getRestCount()>0)
1564         {
1565             Collection<WebServiceOperation> operations = this.getAllowedOperations();
1566             for (WebServiceOperation operation : operations)
1567             {
1568                 String restProduces = operation.getRestProduces();
1569                 if (StringUtils.isNotBlank(restProduces) && restProduces.contains("atom"))
1570                 {
1571                     restAtom = true;
1572                     break;
1573                 }
1574             }
1575             if (!restAtom)
1576             {
1577                 restAtom = StringUtils.isNotBlank(this.getRestProduces()) && this.getRestProduces().indexOf("atom") > -1;
1578             }
1579         }
1580         return restAtom;
1581     }
1582 
1583     /**
1584      * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#handleGetRestCount()
1585      */
1586     @Override
1587     protected int handleGetRestCount()
1588     {
1589         int restCount = 0;
1590         String rest = (String)this.findTaggedValue(WebServiceGlobals.REST);
1591         for (WebServiceOperation operation : this.getAllowedOperations())
1592         {
1593             if (StringUtils.isNotBlank(rest) && (operation.isRest() || rest.equals(BOOLEAN_TRUE)))
1594             {
1595                 restCount++;
1596             }
1597         }
1598         return restCount;
1599     }
1600 
1601     /**
1602      * @see org.andromda.cartridges.webservice.metafacades.WebServiceLogic#handleGetJaxwsCount()
1603      */
1604     @Override
1605     protected int handleGetJaxwsCount()
1606     {
1607         int jaxwsCount = 0;
1608         String rest = (String)this.findTaggedValue(WebServiceGlobals.REST);
1609         for (WebServiceOperation operation : this.getAllowedOperations())
1610         {
1611             if (StringUtils.isBlank(rest) || rest.equals(BOOLEAN_FALSE) && (!operation.isRest()))
1612             {
1613                 jaxwsCount++;
1614             }
1615         }
1616         return jaxwsCount;
1617     }
1618 
1619     /**
1620      * Used to map between XML (list of restricted strings) and Java enum (has both a name and a value).
1621      *
1622      * @return useEnumValueInXSD true if EnumerationLiteral.value is used instead of EnumerationLiteral.Name.
1623      */
1624     public Boolean useEnumValueInXSD()
1625     {
1626         final String propertyName = WebServiceGlobals.USE_ENUM_VALUE_IN_XSD;
1627         // getConfiguredProperty is protected so we must wrap it for use in WebServiceUtils
1628         Object property = this.getConfiguredProperty(propertyName);
1629         if (property != null && String.class.isAssignableFrom(property.getClass()))
1630         {
1631             return Boolean.valueOf(String.valueOf(property)).booleanValue();
1632         }
1633         return Boolean.TRUE;
1634     }
1635 
1636     /**
1637      * @param validationMessages Collection<ModelValidationMessage>
1638      * @see MetafacadeBase#validateInvariants(Collection validationMessages)
1639      */
1640     @Override
1641     public void validateInvariants(Collection<ModelValidationMessage> validationMessages)
1642     {
1643         super.validateInvariants(validationMessages);
1644         try
1645         {
1646             final Object contextElement = this.THIS();
1647             final String name = (String)OCLIntrospector.invoke(contextElement,"name");
1648             boolean constraintValid = OCLExpressions.equal(
1649                 name.substring(0,1).toUpperCase(),
1650                 name.substring(0,1));
1651             if (!constraintValid)
1652             {
1653                 validationMessages.add(
1654                     new ModelValidationMessage(
1655                         (MetafacadeBase)contextElement ,
1656                         "org::andromda::cartridges::webservice::metafacades::WebService::class name must start with an uppercase letter",
1657                         "WebService Class name must start with an uppercase letter."));
1658             }
1659         }
1660         catch (Throwable th)
1661         {
1662             Throwable cause = th.getCause();
1663             int depth = 0; // Some throwables have infinite recursion
1664             while (cause != null && depth < 7)
1665             {
1666                 th = cause;
1667                 depth++;
1668             }
1669             logger.error("Error validating constraint 'org::andromda::cartridges::webservice::WebService::class name must start with an uppercase letter' ON "
1670                 + this.THIS().toString() + ": " + th.getMessage(), th);
1671         }
1672     }
1673 }