001: // THIS SOFTWARE IS PROVIDED BY SOFTARIS PTY.LTD. AND OTHER METABOSS
002: // CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
003: // BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
004: // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOFTARIS PTY.LTD.
005: // OR OTHER METABOSS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
006: // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
007: // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
008: // OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
009: // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
010: // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
011: // EVEN IF SOFTARIS PTY.LTD. OR OTHER METABOSS CONTRIBUTORS ARE ADVISED OF THE
012: // POSSIBILITY OF SUCH DAMAGE.
013: //
014: // Copyright 2000-2005 © Softaris Pty.Ltd. All Rights Reserved.
015: package com.metaboss.sdlctools.models;
016:
017: import javax.jmi.model.Association;
018: import javax.jmi.model.AssociationEnd;
019: import javax.jmi.model.Attribute;
020: import javax.jmi.model.MofClass;
021: import javax.jmi.model.MultiplicityType;
022: import javax.jmi.reflect.JmiException;
023: import javax.jmi.reflect.RefBaseObject;
024: import javax.jmi.reflect.RefObject;
025: import javax.jmi.reflect.WrongSizeException;
026: import javax.naming.Context;
027: import javax.naming.InitialContext;
028: import javax.naming.NamingException;
029:
030: import com.metaboss.sdlctools.models.metabossmodel.ModelElement;
031:
032: /** Specialised exception, which is thrown when model validation has failed */
033: public class ModelValidationException extends ModelRepositoryException {
034: private String[] mErrorMessages = new String[0]; // The raw messages from the exceptions
035: private String[] mErrorExplanations = new String[0]; // Explanation is generated at the time exception is created. This is to avoid model being unloaded and elements being no longer available
036: private String[] mErrorElementsRepositoryIds = new String[0]; // MOFIds for the elements in error are stored at the time exception is created. This is to avoid model being unloaded and elements being no longer available
037: private String[] mErrorMetaBossElementsRefs = new String[0]; // Refs for the elements in error are stored at the time exception is created. This is to avoid model being unloaded and elements being no longer available
038:
039: /** Hidden constructor */
040: private ModelValidationException() {
041: super ();
042: }
043:
044: /** Constructs ModelValidationException object which carries single validation exception */
045: public ModelValidationException(
046: JmiException pConstraintValidationException) {
047: super ("Model validation has failed.");
048: generateErrorExplanations(new JmiException[] { pConstraintValidationException });
049: }
050:
051: /** Constructs ModelValidationException object which carries a number of validation exceptions */
052: public ModelValidationException(
053: JmiException[] pConstraintValidationExceptions) {
054: super ("Model validation has failed.");
055: generateErrorExplanations(pConstraintValidationExceptions);
056: }
057:
058: /** Constructs ModelValidationException object which carries single validation exception and a message */
059: public ModelValidationException(String pMessage,
060: JmiException pConstraintValidationException) {
061: super (pMessage);
062: generateErrorExplanations(new JmiException[] { pConstraintValidationException });
063: }
064:
065: /** Constructs ModelValidationException object which carries an array of validation exceptions and a message */
066: public ModelValidationException(String pMessage,
067: JmiException[] pConstraintValidationExceptions) {
068: super (pMessage);
069: generateErrorExplanations(pConstraintValidationExceptions);
070: }
071:
072: /** Hidden constructor */
073: private ModelValidationException(String pMessage) {
074: super (pMessage);
075: }
076:
077: /** Hidden constructor */
078: private ModelValidationException(String pMessage, Throwable pCause) {
079: super (pMessage, pCause);
080: }
081:
082: /** Hidden constructor */
083: private ModelValidationException(Throwable pCause) {
084: super (pCause);
085: }
086:
087: /** Returns number of separate model validation errors which have occurred */
088: public int getNumberOfErrors() {
089: return mErrorExplanations.length;
090: }
091:
092: /** Returns string with explanation of all failures */
093: public String getFullExplanation() {
094: StringBuffer lExplanation = new StringBuffer();
095: for (int i = 0; i < mErrorExplanations.length; i++) {
096: if (i > 0)
097: lExplanation.append("\n\n");
098: lExplanation.append(mErrorExplanations[i]);
099: }
100: return lExplanation.toString();
101: }
102:
103: /** Returns string with full explanation of an error at the particular index */
104: public String getErrorExplanation(int pErrorIndex) {
105: if (pErrorIndex < 0 || pErrorIndex >= mErrorExplanations.length)
106: throw new IllegalArgumentException(
107: "Error index out of bounds.");
108: return mErrorExplanations[pErrorIndex];
109: }
110:
111: /** Returns string with short error message from the error at the particular index
112: * as it was reported by the validation process. This excludes all additional bits (error element, model element, reported by etc...) */
113: public String getErrorMessage(int pErrorIndex) {
114: if (pErrorIndex < 0 || pErrorIndex >= mErrorMessages.length)
115: throw new IllegalArgumentException(
116: "Error index out of bounds.");
117: return mErrorMessages[pErrorIndex];
118: }
119:
120: /** Returns string with the errorneous MetaBoss model element reference at the particular index.
121: * May return null if this error does not describe MetaBoss model element or
122: * error just does not specify a particular model element at all */
123: public String getErrorModelElementRef(int pErrorIndex) {
124: if (pErrorIndex < 0
125: || pErrorIndex >= mErrorMetaBossElementsRefs.length)
126: throw new IllegalArgumentException(
127: "Error index out of bounds.");
128: return mErrorMetaBossElementsRefs[pErrorIndex];
129: }
130:
131: /** Returns string with the errorneous model element repository id at the particular index.
132: * May return null if this error does not specify a particular model element at all */
133: public String getErrorModelElementRepositoryId(int pErrorIndex) {
134: if (pErrorIndex < 0
135: || pErrorIndex >= mErrorElementsRepositoryIds.length)
136: throw new IllegalArgumentException(
137: "Error index out of bounds.");
138: return mErrorElementsRepositoryIds[pErrorIndex];
139: }
140:
141: // Helper. Explains given list of validation errors.
142: // Better to be called from constructor, when model elements are available
143: // so it can use human readable names
144: // private void generateErrorExplanations(JmiException[] pValidationExceptions)
145: // {
146: // // Occasionally same error is delivered twice - we need to try to combat this situation by filtering out duplicates
147: // Set lAlreadyProcessedValidationExceptions = new HashSet();
148: //
149: // // Create lists, which will be converted to arrays at the end
150: // List lErrorMessages = new ArrayList();
151: // List lErrorExplanations = new ArrayList();
152: // List lErrorElementsRepositoryIds = new ArrayList();
153: // List lErrorMetaBossElementsRefs = new ArrayList();
154: // for (int i = 0; i < pValidationExceptions.length; i++)
155: // {
156: // StringBuffer lExplanation = new StringBuffer();
157: // JmiException lValidationException = pValidationExceptions[i];
158: // RefObject lMetaObjectInError = lValidationException.getElementInError();
159: // RefObject lObjectInError = (RefObject)lValidationException.getObjectInError();
160: // String lValidationExceptionMessage = lValidationException.getMessage();
161: // // Filter out duplicate exceptions
162: // {
163: // StringBuffer lValidationExceptionKey = new StringBuffer();
164: // lValidationExceptionKey.append(lObjectInError != null ? lObjectInError.refMofId() : "null");
165: // lValidationExceptionKey.append(":");
166: // lValidationExceptionKey.append(lMetaObjectInError != null ? lMetaObjectInError.refMofId() : "null");
167: // lValidationExceptionKey.append(":");
168: // lValidationExceptionKey.append(lValidationExceptionMessage != null ? lValidationExceptionMessage : "null");
169: // lValidationExceptionKey.append(":");
170: // lValidationExceptionKey.append(lValidationException.getClass().getName());
171: // if (!lAlreadyProcessedValidationExceptions.add(lValidationExceptionKey.toString()))
172: // continue; // Exact same exception has already been defined
173: // }
174: //
175: // // Work on message. First of all apply special processing to the WrongSizeException
176: // // it usually indicates model constraint violation
177: // if (lValidationException instanceof WrongSizeException)
178: // {
179: // // This type of exception most of the times does not deliver
180: // // element in error, so we have to parse it from the text
181: // String lMofIdPrefix = "Not enough objects linked to ";
182: // String lMofIdSuffix = " at end '";
183: // // Try to convert MOF Id to our ref if it is possible
184: // if (lValidationExceptionMessage != null && lValidationExceptionMessage.startsWith(lMofIdPrefix))
185: // {
186: // int lMofIdPrefixLength = lMofIdPrefix.length();
187: // int lEndOfMofIdIndex = lValidationExceptionMessage.indexOf(lMofIdSuffix);
188: // int lMofIdSuffixLength = lMofIdSuffix.length();
189: // String lMOFId = lValidationExceptionMessage.substring(lMofIdPrefixLength,lEndOfMofIdIndex);
190: // String lEndName = lValidationExceptionMessage.substring(lEndOfMofIdIndex + lMofIdSuffixLength, lValidationExceptionMessage.length()-2);
191: // // Try to resolve the MOF id to the object
192: // try
193: // {
194: // Context lContext = new InitialContext();
195: // ModelRepository lRepository = (ModelRepository)lContext.lookup(ModelRepository.COMPONENT_URL);
196: // RefBaseObject lModelObject = lRepository.getModelObjectByRepositoryId(lMOFId);
197: // // Improve the message for our elements
198: // if (lModelObject instanceof ModelElement)
199: // {
200: // lValidationExceptionMessage = "Reference multiplicity constraint violation. ModelElement in error: " + ((ModelElement)lModelObject).getRef();
201: // }
202: // // Set up object in error if there is none
203: // if ((lObjectInError == null) && (lModelObject instanceof RefObject))
204: // lObjectInError = (RefObject)lModelObject;
205: //
206: // }
207: // catch(NamingException e)
208: // {
209: // // Ignore and just output raw message
210: // lValidationExceptionMessage = lValidationException.getMessage();
211: // }
212: // catch(ModelRepositoryException e)
213: // {
214: // // Ignore and just output raw message
215: // lValidationExceptionMessage = lValidationException.getMessage();
216: // }
217: // catch(Throwable t)
218: // {
219: // // Ignore and just output raw message
220: // lValidationExceptionMessage = lValidationException.getMessage();
221: // }
222: // }
223: // else
224: // if (lValidationExceptionMessage == null)
225: // lValidationExceptionMessage = "Model element reference multiplicity constraint violation.";
226: // }
227: // else
228: // if (lValidationExceptionMessage == null)
229: // lValidationExceptionMessage = "This error is unusual - it does not have any error mesage.";
230: // lExplanation.append("Validation exception " + (i+1) + " of " + pValidationExceptions.length + ": " + lValidationException.getClass().getName());
231: // lExplanation.append("\nMessage: " + lValidationExceptionMessage);
232: // if (lObjectInError != null)
233: // {
234: // String lErrorElementRepositoryId = lObjectInError.refMofId();
235: // lErrorElementsRepositoryIds.add(lErrorElementRepositoryId);
236: // if (lObjectInError instanceof ModelElement)
237: // {
238: // ModelElement lErrorneousModelElement = (ModelElement)lObjectInError;
239: // String lErrorElementRef = lErrorneousModelElement.getRef();
240: // lErrorMetaBossElementsRefs.add(lErrorElementRef);
241: // lExplanation.append("\nModelElement in error: " + lErrorElementRef);
242: // }
243: // else
244: // {
245: // lExplanation.append("\nModelElement in error: " + lErrorElementRepositoryId);
246: // }
247: // }
248: // if (lMetaObjectInError instanceof AssociationEnd)
249: // {
250: // AssociationEnd lErrorneousAssociationEnd = (AssociationEnd)lMetaObjectInError;
251: // Association lErrorneousAssociation = (Association)lErrorneousAssociationEnd.getContainer();
252: // lExplanation.append("\nAssociation in error: " + lErrorneousAssociation.getName() + ". AssociationEnd in error: " + lErrorneousAssociationEnd.getName());
253: // // Report on requred multiplicity if it is relevant
254: // if (lValidationException instanceof WrongSizeException)
255: // {
256: // lExplanation.append(" Expected multiplicity is: ");
257: // lExplanation.append(getMultiplicityString(lErrorneousAssociationEnd.getMultiplicity()));
258: // }
259: // }
260: // else
261: // if (lMetaObjectInError instanceof Attribute)
262: // {
263: // Attribute lErrorneousAttribute = (Attribute)lMetaObjectInError;
264: // MofClass lErrorneousClass = (MofClass)lErrorneousAttribute.getContainer();
265: // lExplanation.append("\nClass in error: " + lErrorneousClass.getName() + ". Attribute in error: " + lErrorneousAttribute.getName());
266: // // Report on requred multiplicity if it is relevant
267: // if (lValidationException instanceof WrongSizeException)
268: // {
269: // lExplanation.append(" Expected multiplicity is: ");
270: // lExplanation.append(getMultiplicityString(lErrorneousAttribute.getMultiplicity()));
271: // }
272: // }
273: // else
274: // if (lMetaObjectInError instanceof MofClass)
275: // {
276: // MofClass lErrorneousClass = (MofClass)lMetaObjectInError;
277: // lExplanation.append("\nClass in error: " + lErrorneousClass.getName());
278: // }
279: // StackTraceElement[] lStackTrace = lValidationException.getStackTrace();
280: // if (lStackTrace != null && lStackTrace.length > 0)
281: // {
282: // StackTraceElement lLastElement = lStackTrace[0];
283: // lExplanation.append("\nReported by " + lLastElement.getClassName());
284: // if (lLastElement.getLineNumber() >= 0)
285: // lExplanation.append(" ( Line " + lLastElement.getLineNumber() + " )");
286: // }
287: // lErrorMessages.add(lValidationExceptionMessage);
288: // lErrorExplanations.add(lExplanation.toString());
289: // }
290: // mErrorMessages = (String[])lErrorMessages.toArray(new String[lErrorMessages.size()]);
291: // mErrorExplanations = (String[])lErrorExplanations.toArray(new String[lErrorExplanations.size()]);
292: // mErrorElementsRepositoryIds = (String[])lErrorElementsRepositoryIds.toArray(new String[lErrorElementsRepositoryIds.size()]);
293: // mErrorMetaBossElementsRefs = (String[])lErrorMetaBossElementsRefs.toArray(new String[lErrorMetaBossElementsRefs.size()]);
294: // }
295:
296: // Helper. Explains given list of validation errors.
297: // Better to be called from constructor, when model elements are available
298: // so it can use human readable names
299: private void generateErrorExplanations(
300: JmiException[] pValidationExceptions) {
301: // Create arrays
302: mErrorMessages = new String[pValidationExceptions.length];
303: mErrorExplanations = new String[pValidationExceptions.length];
304: mErrorElementsRepositoryIds = new String[pValidationExceptions.length];
305: mErrorMetaBossElementsRefs = new String[pValidationExceptions.length];
306: for (int i = 0; i < pValidationExceptions.length; i++) {
307: StringBuffer lExplanation = new StringBuffer();
308: JmiException lValidationException = pValidationExceptions[i];
309: RefObject lMetaObjectInError = lValidationException
310: .getElementInError();
311: RefObject lObjectInError = (RefObject) lValidationException
312: .getObjectInError();
313: String lValidationExceptionMessage = lValidationException
314: .getMessage();
315: // Work on message. First of all apply special processing to the WrongSizeException
316: // it usually indicates model constraint violation
317: if (lValidationException instanceof WrongSizeException) {
318: // This type of exception most of the times does not deliver
319: // element in error, so we have to parse it from the text
320: String lMofIdPrefix = "Not enough objects linked to ";
321: String lMofIdSuffix = " at end '";
322: // Try to convert MOF Id to our ref if it is possible
323: if (lValidationExceptionMessage != null
324: && lValidationExceptionMessage
325: .startsWith(lMofIdPrefix)) {
326: int lMofIdPrefixLength = lMofIdPrefix.length();
327: int lEndOfMofIdIndex = lValidationExceptionMessage
328: .indexOf(lMofIdSuffix);
329: int lMofIdSuffixLength = lMofIdSuffix.length();
330: String lMOFId = lValidationExceptionMessage
331: .substring(lMofIdPrefixLength,
332: lEndOfMofIdIndex);
333: String lEndName = lValidationExceptionMessage
334: .substring(lEndOfMofIdIndex
335: + lMofIdSuffixLength,
336: lValidationExceptionMessage
337: .length() - 2);
338: // Try to resolve the MOF id to the object
339: try {
340: Context lContext = new InitialContext();
341: ModelRepository lRepository = (ModelRepository) lContext
342: .lookup(ModelRepository.COMPONENT_URL);
343: RefBaseObject lModelObject = lRepository
344: .getModelObjectByRepositoryId(lMOFId);
345: // Improve the message for our elements
346: if (lModelObject instanceof ModelElement) {
347: lValidationExceptionMessage = "Reference multiplicity constraint violation. ModelElement in error: "
348: + ((ModelElement) lModelObject)
349: .getRef();
350: }
351: // Set up object in error if there is none
352: if ((lObjectInError == null)
353: && (lModelObject instanceof RefObject))
354: lObjectInError = (RefObject) lModelObject;
355:
356: } catch (NamingException e) {
357: // Ignore and just output raw message
358: lValidationExceptionMessage = lValidationException
359: .getMessage();
360: } catch (ModelRepositoryException e) {
361: // Ignore and just output raw message
362: lValidationExceptionMessage = lValidationException
363: .getMessage();
364: } catch (Throwable t) {
365: // Ignore and just output raw message
366: lValidationExceptionMessage = lValidationException
367: .getMessage();
368: }
369: } else if (lValidationExceptionMessage == null)
370: lValidationExceptionMessage = "Model element reference multiplicity constraint violation.";
371: } else if (lValidationExceptionMessage == null)
372: lValidationExceptionMessage = "This error is unusual - it does not have any error mesage.";
373: lExplanation.append("Validation exception " + (i + 1)
374: + " of " + pValidationExceptions.length + ": "
375: + lValidationException.getClass().getName());
376: lExplanation.append("\nMessage: "
377: + lValidationExceptionMessage);
378: if (lObjectInError != null) {
379: String lErrorElementRepositoryId = mErrorElementsRepositoryIds[i] = lObjectInError
380: .refMofId();
381: if (lObjectInError instanceof ModelElement) {
382: ModelElement lErrorneousModelElement = (ModelElement) lObjectInError;
383: String lErrorElementRef = mErrorMetaBossElementsRefs[i] = lErrorneousModelElement
384: .getRef();
385: lExplanation.append("\nModelElement in error: "
386: + lErrorElementRef);
387: } else {
388: lExplanation.append("\nModelElement in error: "
389: + lErrorElementRepositoryId);
390: }
391: }
392: if (lMetaObjectInError instanceof AssociationEnd) {
393: AssociationEnd lErrorneousAssociationEnd = (AssociationEnd) lMetaObjectInError;
394: Association lErrorneousAssociation = (Association) lErrorneousAssociationEnd
395: .getContainer();
396: lExplanation.append("\nAssociation in error: "
397: + lErrorneousAssociation.getName()
398: + ". AssociationEnd in error: "
399: + lErrorneousAssociationEnd.getName());
400: // Report on requred multiplicity if it is relevant
401: if (lValidationException instanceof WrongSizeException) {
402: lExplanation.append(" Expected multiplicity is: ");
403: lExplanation
404: .append(getMultiplicityString(lErrorneousAssociationEnd
405: .getMultiplicity()));
406: }
407: } else if (lMetaObjectInError instanceof Attribute) {
408: Attribute lErrorneousAttribute = (Attribute) lMetaObjectInError;
409: MofClass lErrorneousClass = (MofClass) lErrorneousAttribute
410: .getContainer();
411: lExplanation.append("\nClass in error: "
412: + lErrorneousClass.getName()
413: + ". Attribute in error: "
414: + lErrorneousAttribute.getName());
415: // Report on requred multiplicity if it is relevant
416: if (lValidationException instanceof WrongSizeException) {
417: lExplanation.append(" Expected multiplicity is: ");
418: lExplanation
419: .append(getMultiplicityString(lErrorneousAttribute
420: .getMultiplicity()));
421: }
422: } else if (lMetaObjectInError instanceof MofClass) {
423: MofClass lErrorneousClass = (MofClass) lMetaObjectInError;
424: lExplanation.append("\nClass in error: "
425: + lErrorneousClass.getName());
426: }
427: StackTraceElement[] lStackTrace = lValidationException
428: .getStackTrace();
429: if (lStackTrace != null && lStackTrace.length > 0) {
430: StackTraceElement lLastElement = lStackTrace[0];
431: lExplanation.append("\nReported by "
432: + lLastElement.getClassName());
433: if (lLastElement.getLineNumber() >= 0)
434: lExplanation.append(" ( Line "
435: + lLastElement.getLineNumber() + " )");
436: }
437: mErrorMessages[i] = lValidationExceptionMessage;
438: mErrorExplanations[i] = lExplanation.toString();
439: }
440: }
441:
442: // Helper. Returns string representation of the multiplicity
443: private static String getMultiplicityString(
444: MultiplicityType pMultiplicity) {
445: StringBuffer lReturnBuffer = new StringBuffer();
446: if (pMultiplicity.getLower() == pMultiplicity.getUpper()) {
447: lReturnBuffer.append(Integer.toString(pMultiplicity
448: .getUpper()));
449: } else {
450: lReturnBuffer.append(Integer.toString(pMultiplicity
451: .getLower()));
452: lReturnBuffer.append("..");
453: if (pMultiplicity.getUpper() >= 0)
454: lReturnBuffer.append(Integer.toString(pMultiplicity
455: .getUpper()));
456: else
457: lReturnBuffer.append("*");
458: }
459: return lReturnBuffer.toString();
460: }
461: }
|