001: /*
002: * The contents of this file are subject to the terms of the Common Development
003: * and Distribution License (the License). You may not use this file except in
004: * compliance with the License.
005: *
006: * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
007: * or http://www.netbeans.org/cddl.txt.
008: *
009: * When distributing Covered Code, include this CDDL Header Notice in each file
010: * and include the License file at http://www.netbeans.org/cddl.txt.
011: * If applicable, add the following below the CDDL Header, with the fields
012: * enclosed by brackets [] replaced by your own identifying information:
013: * "Portions Copyrighted [year] [name of copyright owner]"
014: *
015: * Portions Copyrighted 2007 Sun Microsystems, Inc.
016: */
017:
018: package org.netbeans.modules.bpel.model.api.support;
019:
020: import java.util.ArrayList;
021: import java.util.Collection;
022: import java.util.List;
023: import javax.xml.namespace.QName;
024: import org.netbeans.modules.bpel.model.api.BpelEntity;
025: import org.netbeans.modules.xml.xpath.ext.spi.VariableResolver;
026: import org.netbeans.modules.xml.schema.model.ReferenceableSchemaComponent;
027: import org.netbeans.modules.xml.xam.spi.Validator.ResultType;
028: import org.netbeans.modules.bpel.model.api.BpelModel;
029: import org.netbeans.modules.bpel.model.api.Process;
030: import org.netbeans.modules.bpel.model.api.VariableDeclaration;
031: import org.netbeans.modules.bpel.model.api.references.WSDLReference;
032: import org.netbeans.modules.xml.wsdl.model.Message;
033: import org.netbeans.modules.xml.wsdl.model.Part;
034: import org.netbeans.modules.xml.xam.Model.State;
035: import org.openide.util.NbBundle;
036:
037: /**
038: * This object is intended to allow to an XPath model to resolve BPEL variables.
039: *
040: * @author nk160297
041: */
042: public class BpelVariableResolver implements
043: VariableResolver<XPathBpelVariable> {
044:
045: private PathValidationContext myVContext;
046: private BpelEntity mBpelEntity;
047: private VisibilityScope mVisScope;
048:
049: public BpelVariableResolver(PathValidationContext context,
050: BpelEntity bpelEntity) {
051: myVContext = context;
052: mBpelEntity = bpelEntity;
053: }
054:
055: private synchronized VisibilityScope getVisibilityScope() {
056: if (mVisScope == null) {
057: mVisScope = new VisibilityScope(mBpelEntity);
058: }
059: return mVisScope;
060: }
061:
062: public XPathBpelVariable resolveVariable(QName varQName) {
063: Part resultPart = null;
064: VariableDeclaration resultVariable = null;
065: //
066: String prefix = varQName.getPrefix();
067: if (prefix != null && prefix.length() != 0) {
068: BpelModel bpelModel = mBpelEntity.getBpelModel();
069: if (bpelModel == null
070: || bpelModel.getState() != State.VALID) {
071: // Error: invalid bpel model
072: return null;
073: }
074: Process process = bpelModel.getProcess();
075: if (process == null) {
076: // Error: invalid process
077: return null;
078: }
079: //
080: ExNamespaceContext nsContext = mBpelEntity
081: .getNamespaceContext();
082: //
083: String namespaceUri = nsContext.getNamespaceURI(prefix);
084: if (namespaceUri == null) {
085: // Error: Unknown prefix
086: if (myVContext != null) {
087: myVContext
088: .addResultItem(
089: ResultType.ERROR,
090: NbBundle.getMessage(
091: BpelVariableResolver.class,
092: "UNKNOWN_NAMESPACE_PREFIX"),
093: prefix); // NOI18N
094: }
095: return null;
096: }
097: //
098: String processNsUri = process.getTargetNamespace();
099: assert processNsUri != null;
100: //
101: if (!processNsUri.equals(namespaceUri)) {
102: // Error: the variable is defined in a wrong namespace.
103: String correctPrefix = nsContext
104: .getPrefix(processNsUri);
105: String varName = varQName.getLocalPart();
106: if (myVContext != null) {
107: myVContext.addResultItem(ResultType.ERROR, NbBundle
108: .getMessage(BpelVariableResolver.class,
109: "WRONG_VARIABLE_PREFIX"), varName,
110: prefix, correctPrefix); // NOI18N
111: }
112: return null;
113: }
114: }
115: //
116: // Extract part
117: String varName = varQName.getLocalPart();
118: int partIndex = varName.lastIndexOf('.');
119: String partName = null;
120: if (partIndex != -1) {
121: partName = varName.substring(partIndex + 1);
122: varName = varName.substring(0, partIndex);
123: }
124: //
125: // Try to find the variable in the model.
126: // Visibility rules are taken into consideration!
127: resultVariable = getVisibilityScope().lookForVariable(varName);
128: if (resultVariable == null) {
129: // Error: Can't find the variable
130: //
131: // Don't show this error because of it is already detected by another
132: // See: ReferencesValidator.FIX_VARIABLE
133: return null;
134: }
135: //
136: // Check message type
137: WSDLReference<Message> messageTypeRef = resultVariable
138: .getMessageType();
139: Message message = null;
140: if (messageTypeRef != null) {
141: message = messageTypeRef.get();
142: if (message == null) {
143: // Error: impossible to get message by ref
144: if (myVContext != null) {
145: myVContext.addResultItem(ResultType.ERROR, NbBundle
146: .getMessage(BpelVariableResolver.class,
147: "CANT_RETRIEVE_MESSAGE_TYPE"),
148: messageTypeRef.getRefString(), varName); // NOI18N
149: }
150: return null;
151: }
152: }
153: //
154: // Check part
155: if (partName == null || partName.length() == 0) {
156: if (messageTypeRef != null) {
157: //
158: // Error: If the variable is of message type then a part has to be specified
159: //
160: if (myVContext != null) {
161: ArrayList<String> partNameList = getPartNames(message);
162: switch (partNameList.size()) {
163: case 0:
164: myVContext.addResultItem(ResultType.ERROR,
165: NbBundle.getMessage(
166: BpelVariableResolver.class,
167: "MESSAGE_PART_REQUIRED"),
168: varName); // NOI18N
169: break;
170: case 1:
171: String firstPartName = partNameList.get(0);
172: myVContext
173: .addResultItem(
174: ResultType.ERROR,
175: NbBundle
176: .getMessage(
177: BpelVariableResolver.class,
178: "SPECIFIC_MESSAGE_PART_REQUIRED"),
179: varName, firstPartName); // NOI18N
180: break;
181: default:
182: //
183: myVContext.addResultItem(ResultType.ERROR,
184: NbBundle.getMessage(
185: BpelVariableResolver.class,
186: "A_MESSAGE_PART_REQUIRED"),
187: varName,
188: partNameListToString(partNameList)); // NOI18N
189: }
190: }
191: //
192: return null;
193: }
194: } else {
195: // A message part is specified
196: if (messageTypeRef == null) {
197: // Error: if the part is specified then variable has to be of a message type
198: if (myVContext != null) {
199: myVContext.addResultItem(ResultType.ERROR, NbBundle
200: .getMessage(BpelVariableResolver.class,
201: "VARIABLE_MESSAGE_TYPE_REQUIRED"),
202: varName); // NOI18N
203: }
204: return null;
205: } else {
206: Collection<Part> parts = message.getParts();
207: for (Part aPart : parts) {
208: if (aPart.getName().equals(partName)) {
209: resultPart = aPart;
210: break;
211: }
212: }
213: //
214: if (resultPart == null) {
215: // Error: the specified part is not found
216: //
217: if (myVContext != null) {
218: ArrayList<String> partNameList = getPartNames(message);
219: switch (partNameList.size()) {
220: case 0:
221: myVContext.addResultItem(ResultType.ERROR,
222: NbBundle.getMessage(
223: BpelVariableResolver.class,
224: "UNKNOWN_MESSAGE_PART"),
225: partName, varName); // NOI18N
226: break;
227: case 1:
228: String firstPartName = partNameList.get(0);
229: myVContext
230: .addResultItem(
231: ResultType.ERROR,
232: NbBundle
233: .getMessage(
234: BpelVariableResolver.class,
235: "SPECIFIC_UNKNOWN_MESSAGE_PART"),
236: partName, varName,
237: firstPartName); // NOI18N
238: break;
239: default:
240: //
241: myVContext.addResultItem(ResultType.ERROR,
242: NbBundle.getMessage(
243: BpelVariableResolver.class,
244: "A_UNKNOWN_MESSAGE_PART"),
245: partName, varName,
246: partNameListToString(partNameList)); // NOI18N
247: }
248: }
249: return null;
250: }
251: }
252: }
253: return new XPathBpelVariable(resultVariable, resultPart);
254: }
255:
256: public ReferenceableSchemaComponent resolveVariableType(
257: XPathBpelVariable variable) {
258: if (variable != null) {
259: return variable.getType();
260: } else {
261: return null;
262: }
263: }
264:
265: public ReferenceableSchemaComponent resolveVariableType(
266: QName variableName) {
267: return resolveVariableType(resolveVariable(variableName));
268: }
269:
270: //==========================================================================
271:
272: private ArrayList<String> getPartNames(Message message) {
273: ArrayList<String> partNameList = new ArrayList<String>();
274: Collection<Part> parts = message.getParts();
275: for (Part aPart : parts) {
276: String aPartName = aPart.getName();
277: partNameList.add(aPartName);
278: }
279: return partNameList;
280: }
281:
282: private String partNameListToString(List<String> partNameList) {
283: StringBuilder sb = new StringBuilder();
284: boolean isFirst = true;
285: for (String aPartName : partNameList) {
286: if (isFirst) {
287: isFirst = false;
288: } else {
289: sb.append(" | "); // NOI18N
290: }
291: //
292: sb.append(aPartName);
293: }
294: return sb.toString();
295: }
296: }
|