001: /*
002: Copyright (c) 2007, Dennis M. Sosnoski
003: All rights reserved.
004:
005: Redistribution and use in source and binary forms, with or without modification,
006: are permitted provided that the following conditions are met:
007:
008: * Redistributions of source code must retain the above copyright notice, this
009: list of conditions and the following disclaimer.
010: * Redistributions in binary form must reproduce the above copyright notice,
011: this list of conditions and the following disclaimer in the documentation
012: and/or other materials provided with the distribution.
013: * Neither the name of JiBX nor the names of its contributors may be used
014: to endorse or promote products derived from this software without specific
015: prior written permission.
016:
017: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
018: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
019: WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
020: DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
021: ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
022: (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
023: LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
024: ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025: (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
026: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027: */
028:
029: package org.jibx.ws.wsdl;
030:
031: import java.lang.reflect.Modifier;
032: import java.util.ArrayList;
033: import java.util.HashMap;
034: import java.util.List;
035: import java.util.Map;
036: import java.util.Set;
037:
038: import org.jibx.binding.generator.CustomBase;
039: import org.jibx.binding.generator.SharedNestingBase;
040: import org.jibx.binding.model.DocumentFormatter;
041: import org.jibx.binding.model.IClass;
042: import org.jibx.binding.model.IClassItem;
043: import org.jibx.binding.model.IClassLocator;
044: import org.jibx.runtime.IUnmarshallingContext;
045: import org.jibx.runtime.JiBXException;
046: import org.jibx.runtime.impl.UnmarshallingContext;
047:
048: /**
049: * Service customization information. This supports direct service
050: * customizations (such as the corresponding request and/or response element
051: * name) and also acts as a container for parameter and/or return
052: * customizations.
053: */
054: public class ServiceCustom extends NestingBase {
055: // values specific to service level
056: private final String m_className;
057: private String m_serviceName;
058: private String m_portName;
059: private String m_bindingName;
060: private String m_portTypeName;
061: private String m_wsdlNamespace;
062: private String m_serviceAddress;
063: private List m_documentation;
064: private String[] m_includes;
065: private String[] m_excludes;
066:
067: // list of contained operation customizations
068: private final ArrayList m_operations;
069:
070: // values filled in by apply() method
071: private IClass m_classInformation;
072: private String m_namespace;
073:
074: /**
075: * Constructor.
076: *
077: * @param parent
078: * @param clas
079: */
080: public ServiceCustom(SharedNestingBase parent, String clas) {
081: super (parent);
082: m_className = clas;
083: m_operations = new ArrayList();
084: }
085:
086: /**
087: * Get service class name.
088: *
089: * @return class name
090: */
091: public String getClassName() {
092: return m_className;
093: }
094:
095: /**
096: * Get the service name.
097: *
098: * @return service name
099: */
100: public String getServiceName() {
101: return m_serviceName;
102: }
103:
104: /**
105: * Get the port name.
106: *
107: * @return port name
108: */
109: public String getPortName() {
110: return m_portName;
111: }
112:
113: /**
114: * Get the binding name.
115: *
116: * @return binding name
117: */
118: public String getBindingName() {
119: return m_bindingName;
120: }
121:
122: /**
123: * Get the portType name.
124: *
125: * @return portType name
126: */
127: public String getPortTypeName() {
128: return m_portTypeName;
129: }
130:
131: /**
132: * Get the service address.
133: *
134: * @return service address
135: */
136: public String getServiceAddress() {
137: return m_serviceAddress;
138: }
139:
140: /**
141: * Get service documentation node list.
142: *
143: * @return list of documentation nodes (<code>null</code> if none)
144: */
145: public List getDocumentation() {
146: return m_documentation;
147: }
148:
149: /**
150: * Get list of method names to be excluded as operations.
151: *
152: * @return excludes (<code>null</code> if none)
153: */
154: public String[] getExcludes() {
155: return m_excludes;
156: }
157:
158: /**
159: * Get list of method names to be included as operations.
160: *
161: * @return includes (<code>null</code> if none)
162: */
163: public String[] getIncludes() {
164: return m_includes;
165: }
166:
167: /**
168: * Get list of children.
169: *
170: * @return list
171: */
172: public ArrayList getOperations() {
173: return m_operations;
174: }
175:
176: /**
177: * Get the namespace for WSDL definitions of this service. This value is
178: * set by the {@link #apply(IClassLocator)} method.
179: *
180: * @return WSDL namespace
181: */
182: public String getWsdlNamespace() {
183: return m_wsdlNamespace;
184: }
185:
186: /**
187: * Add child.
188: *
189: * @param child
190: */
191: protected void addChild(CustomBase child) {
192: if (child.getParent() == this ) {
193: m_operations.add(child);
194: } else {
195: throw new IllegalStateException(
196: "Internal error: child not linked");
197: }
198: }
199:
200: /**
201: * Unmarshalling factory. This gets the containing element and the name so
202: * that the standard constructor can be used.
203: *
204: * @param ictx
205: * @return created instance
206: * @throws JiBXException
207: */
208: private static ServiceCustom factory(IUnmarshallingContext ictx)
209: throws JiBXException {
210: UnmarshallingContext uctx = (UnmarshallingContext) ictx;
211: return new ServiceCustom(getContainingClass(ictx), uctx
212: .attributeText(null, "class"));
213: }
214:
215: /**
216: * Apply customizations to service to fill out members.
217: *
218: * @param icl class locator
219: */
220: public void apply(IClassLocator icl) {
221:
222: // find the service class information
223: m_classInformation = icl.getClassInfo(m_className);
224:
225: // create documentation formatter
226: DocumentFormatter fmt = new DocumentFormatter();
227:
228: // fill in any missing details
229: int split = m_className.lastIndexOf('.');
230: if (m_serviceName == null) {
231: String simple = m_className.substring(split + 1);
232: String name = convertName(simple, UPPER_CAMEL_CASE_NAMES);
233: m_serviceName = registerName(name, this );
234: } else if (!m_serviceName.equals(registerName(m_serviceName,
235: this ))) {
236: throw new IllegalStateException(
237: "Service name conflict for '" + m_serviceName
238: + '\'');
239: }
240: if (m_portName == null) {
241: m_portName = m_serviceName + "Port";
242: }
243: if (m_bindingName == null) {
244: m_bindingName = m_serviceName + "Binding";
245: }
246: if (m_portTypeName == null) {
247: m_portTypeName = m_serviceName + "PortType";
248: }
249: String uri = getSpecifiedNamespace();
250: if (uri == null) {
251: uri = deriveNamespace(getParent().getNamespace(),
252: m_className, getNamespaceStyle());
253: }
254: setNamespace(uri);
255: if (m_wsdlNamespace == null) {
256:
257: // no WSDL namespace set, check parent setting
258: String ns = ((NestingBase) getParent()).getWsdlNamespace();
259: if (ns == null) {
260:
261: // no setting, use class package and service name
262:
263: m_wsdlNamespace = packageToNamespace(packageOfType(m_className))
264: + '/' + m_serviceName;
265:
266: } else {
267:
268: // append service name to supplied setting
269: if (ns.endsWith("/")) {
270: m_wsdlNamespace = ns + m_serviceName;
271: } else {
272: m_wsdlNamespace = ns + '/' + m_serviceName;
273: }
274: }
275: }
276: if (m_serviceAddress == null) {
277: String base = getServiceBase();
278: if (base != null) {
279: StringBuffer buff = new StringBuffer(base);
280: if (!base.endsWith("/")) {
281: buff.append('/');
282: }
283: buff.append(m_serviceName);
284: m_serviceAddress = buff.toString();
285: }
286: }
287: if (m_documentation == null) {
288: m_documentation = fmt.docToNodes(m_classInformation
289: .getJavaDoc());
290: }
291:
292: // register any predefined operation children
293: for (int i = 0; i < m_operations.size(); i++) {
294: OperationCustom op = (OperationCustom) m_operations.get(i);
295: String name = op.getOperationName();
296: if (name != null) {
297: if (registerName(name, op) != name) {
298: throw new IllegalStateException(
299: "Duplicate operation name " + name);
300: }
301: }
302: }
303:
304: // generate an operation for each exposed method in service class
305: Set inclset = nameSet(m_includes);
306: Set exclset = nameSet(m_excludes);
307: Map opmap = new HashMap();
308: for (int i = 0; i < m_operations.size(); i++) {
309: OperationCustom op = (OperationCustom) m_operations.get(i);
310: opmap.put(op.getMethodName().toLowerCase(), op);
311: }
312: IClassItem[] methods = m_classInformation.getMethods();
313: for (int i = 0; i < methods.length; i++) {
314: IClassItem method = methods[i];
315: String name = method.getName();
316: String lcname = name.toLowerCase();
317: int access = method.getAccessFlags();
318: OperationCustom op = (OperationCustom) opmap.get(lcname);
319: if (op == null) {
320: if (!Modifier.isStatic(access)
321: && !Modifier.isTransient(access)
322: && !"<init>".equals(name)) {
323: boolean use = true;
324: if (inclset != null) {
325: use = inclset.contains(lcname);
326: } else if (exclset != null) {
327: use = !exclset.contains(lcname);
328: }
329: if (use) {
330: op = new OperationCustom(this, name);
331: m_operations.add(op);
332: }
333: }
334: }
335: if (op != null) {
336: op.apply(method, icl, fmt);
337: }
338: }
339: }
340: }
|