0001: // THIS SOFTWARE IS PROVIDED BY SOFTARIS PTY.LTD. AND OTHER METABOSS
0002: // CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
0003: // BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
0004: // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOFTARIS PTY.LTD.
0005: // OR OTHER METABOSS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
0006: // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0007: // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
0008: // OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
0009: // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
0010: // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
0011: // EVEN IF SOFTARIS PTY.LTD. OR OTHER METABOSS CONTRIBUTORS ARE ADVISED OF THE
0012: // POSSIBILITY OF SUCH DAMAGE.
0013: //
0014: // Copyright 2000-2005 © Softaris Pty.Ltd. All Rights Reserved.
0015: package com.metaboss.sdlctools.models.modelassistant.metabossmodel.domainsupport;
0016:
0017: import java.util.ArrayList;
0018: import java.util.Collection;
0019: import java.util.HashSet;
0020: import java.util.Iterator;
0021: import java.util.List;
0022: import java.util.Set;
0023:
0024: import javax.jmi.reflect.ConstraintViolationException;
0025: import javax.jmi.reflect.RefObject;
0026:
0027: import com.metaboss.sdlctools.models.metabossmodel.ModelElementConstraint;
0028: import com.metaboss.sdlctools.models.metabossmodel.datadictionarymodel.Structure;
0029: import com.metaboss.sdlctools.models.metabossmodel.enterprisemodel.Message;
0030: import com.metaboss.sdlctools.models.metabossmodel.enterprisemodel.Operation;
0031: import com.metaboss.sdlctools.models.metabossmodel.enterprisemodel.OperationInputField;
0032: import com.metaboss.sdlctools.models.metabossmodel.enterprisemodel.OperationOutputField;
0033: import com.metaboss.sdlctools.models.metabossmodel.enterprisemodel.OperationOutputMessage;
0034: import com.metaboss.sdlctools.models.metabossmodel.enterprisemodel.Service;
0035: import com.metaboss.sdlctools.models.metabossmodel.enterprisemodel.Servicemodule;
0036: import com.metaboss.sdlctools.models.metabossmodel.enterprisemodel.TransactionPolicyEnum;
0037: import com.metaboss.sdlctools.models.metabossmodel.enterprisemodel.systemimplementationmodel.AggregationTypeEnum;
0038: import com.metaboss.sdlctools.models.metabossmodel.enterprisemodel.systemimplementationmodel.AssociationRole;
0039: import com.metaboss.sdlctools.models.metabossmodel.enterprisemodel.systemimplementationmodel.AssociationRoleCardinalityEnum;
0040: import com.metaboss.sdlctools.models.metabossmodel.enterprisemodel.systemimplementationmodel.Domain;
0041: import com.metaboss.sdlctools.models.metabossmodel.enterprisemodel.systemimplementationmodel.Entity;
0042: import com.metaboss.util.StringUtils;
0043:
0044: /** This class containse helper methods dealing with the Domain Support Servicemodule model element */
0045: class TargetRemoveReferencedEntityOperationHelper {
0046: private ModelAssistantImpl mModelAssistantImpl;
0047:
0048: TargetRemoveReferencedEntityOperationHelper(
0049: ModelAssistantImpl pModelAssistantImpl) {
0050: mModelAssistantImpl = pModelAssistantImpl;
0051: // Add entity Name attribute change listener
0052: mModelAssistantImpl
0053: .addAttributeChangeListener(
0054: Entity.class,
0055: "Name",
0056: new ModelAssistantImpl.ModelElementAttributeChangeListener() {
0057: public void onAttributeBeingUpdated(
0058: RefObject pModelElementBeingUpdated,
0059: String pAttributeName,
0060: Object pOldValue, Object pNewValue) {
0061: Entity lEntity = (Entity) pModelElementBeingUpdated;
0062: Domain lDomain = lEntity.getDomain();
0063: if (lDomain == null)
0064: return; // Entity is not associated with domain
0065: String lDomainName = lDomain.getName();
0066: if (lDomainName == null)
0067: return; // Domain does not have a name
0068: com.metaboss.sdlctools.models.metabossmodel.enterprisemodel.System lSystem = lDomain
0069: .getSystem();
0070: if (lSystem == null)
0071: return; // Domain is not associated with system
0072: Servicemodule lServicemodule = lSystem
0073: .findServicemodule(StylesheetImpl
0074: .getDomainSupportServicemoduleName(lDomainName));
0075: if (lServicemodule == null)
0076: return; // There is no support servicemodule yet
0077: Service lDomainSupportService = lServicemodule
0078: .findService(StylesheetImpl
0079: .getDataManagementServiceName(lDomainName));
0080: if (lDomainSupportService == null)
0081: return; // There is no domain support service yet
0082: // Iterate through references and ensure that the name change is accounted for
0083: for (Iterator lEntityReferencesIterator = lEntity
0084: .getCombinedReferences()
0085: .iterator(); lEntityReferencesIterator
0086: .hasNext();) {
0087: AssociationRole lReference = (AssociationRole) lEntityReferencesIterator
0088: .next();
0089: String lReferencePluralName = lReference
0090: .getPluralName();
0091: if (lReferencePluralName == null)
0092: continue; // Reference does not have a plural name yet
0093: if (pNewValue == null) {
0094: // Only old value is known - ensure that the element is deleted
0095: ensureAbsent(
0096: lDomainSupportService,
0097: (String) pOldValue,
0098: lReferencePluralName);
0099: } else {
0100: // New value is known - analyse the criteria and deal with the element accordingly
0101: AssociationRole lOppositeRole = lReference
0102: .getOppositeRole();
0103: if (lOppositeRole != null
0104: && lReference
0105: .isPlural()
0106: && lOppositeRole
0107: .isPlural()
0108: && AggregationTypeEnum.AGGREGATION
0109: .equals(lOppositeRole
0110: .getAggregationType())) {
0111: // The element must be present - rename or create
0112: if (pOldValue != null)
0113: ensureRenamedPresent(
0114: lDomainSupportService,
0115: lReference,
0116: (String) pOldValue,
0117: (String) pNewValue,
0118: lReferencePluralName,
0119: lReferencePluralName);
0120: else
0121: ensurePresent(
0122: lDomainSupportService,
0123: lReference,
0124: (String) pNewValue,
0125: lReferencePluralName);
0126: } else {
0127: // The element must be absent - delete
0128: ensureAbsent(
0129: lDomainSupportService,
0130: (String) pNewValue,
0131: lReferencePluralName);
0132: if (pOldValue != null)
0133: ensureAbsent(
0134: lDomainSupportService,
0135: (String) pOldValue,
0136: lReferencePluralName);
0137: }
0138: }
0139: }
0140: }
0141: });
0142:
0143: // Add reference pluralName attribute change listener
0144: mModelAssistantImpl
0145: .addAttributeChangeListener(
0146: AssociationRole.class,
0147: "pluralName",
0148: new ModelAssistantImpl.ModelElementAttributeChangeListener() {
0149: public void onAttributeBeingUpdated(
0150: RefObject pModelElementBeingUpdated,
0151: String pAttributeName,
0152: Object pOldValue, Object pNewValue) {
0153: AssociationRole lReference = (AssociationRole) pModelElementBeingUpdated;
0154: Entity lEntity = lReference
0155: .getReferencingEntity();
0156: if (lEntity == null)
0157: return; // Attribute is not associated with entity
0158: Domain lDomain = lEntity.getDomain();
0159: if (lDomain == null)
0160: return; // Entity is not associated with domain
0161: String lDomainName = lDomain.getName();
0162: if (lDomainName == null)
0163: return; // Domain does not have a name
0164: com.metaboss.sdlctools.models.metabossmodel.enterprisemodel.System lSystem = lDomain
0165: .getSystem();
0166: if (lSystem == null)
0167: return; // Domain is not associated with system
0168: Servicemodule lServicemodule = lSystem
0169: .findServicemodule(StylesheetImpl
0170: .getDomainSupportServicemoduleName(lDomainName));
0171: if (lServicemodule == null)
0172: return; // There is no support servicemodule yet
0173: Service lDomainSupportService = lServicemodule
0174: .findService(StylesheetImpl
0175: .getDataManagementServiceName(lDomainName));
0176: if (lDomainSupportService == null)
0177: return; // There is no domain support service yet
0178: AssociationRole lOppositeRole = lReference
0179: .getOppositeRole();
0180: // Iterate through all entities containing this reference and ensure that the change is reflected
0181: Set lAllEntitiesToConsider = new HashSet();
0182: lAllEntitiesToConsider.add(lEntity);
0183: lAllEntitiesToConsider.addAll(lEntity
0184: .getCombinedSubtypes());
0185: for (Iterator lEntityElementsIterator = lAllEntitiesToConsider
0186: .iterator(); lEntityElementsIterator
0187: .hasNext();) {
0188: Entity lEntityElement = (Entity) lEntityElementsIterator
0189: .next();
0190: String lEntityName = lEntityElement
0191: .getName();
0192: if (lEntityName == null)
0193: continue; // Entity does not have a name
0194: if (pNewValue == null) {
0195: // Only old value is known - ensure that the element is deleted
0196: ensureAbsent(
0197: lDomainSupportService,
0198: lEntityName,
0199: (String) pOldValue);
0200: } else {
0201: // New value is known - analyse the criteria and deal with the element accordingly
0202: if (lOppositeRole != null
0203: && lReference
0204: .isPlural()
0205: && lOppositeRole
0206: .isPlural()
0207: && AggregationTypeEnum.AGGREGATION
0208: .equals(lOppositeRole
0209: .getAggregationType())) {
0210: // The element must be present - rename or create
0211: if (pOldValue != null)
0212: ensureRenamedPresent(
0213: lDomainSupportService,
0214: lReference,
0215: lEntityName,
0216: lEntityName,
0217: (String) pOldValue,
0218: (String) pNewValue);
0219: else
0220: ensurePresent(
0221: lDomainSupportService,
0222: lReference,
0223: lEntityName,
0224: (String) pNewValue);
0225: } else {
0226: // The element must be absent - delete
0227: ensureAbsent(
0228: lDomainSupportService,
0229: lEntityName,
0230: (String) pNewValue);
0231: if (pOldValue != null)
0232: ensureAbsent(
0233: lDomainSupportService,
0234: lEntityName,
0235: (String) pOldValue);
0236: }
0237: }
0238: }
0239: }
0240: });
0241:
0242: // Add reference cardinality attribute change listener
0243: mModelAssistantImpl
0244: .addAttributeChangeListener(
0245: AssociationRole.class,
0246: "cardinality",
0247: new ModelAssistantImpl.ModelElementAttributeChangeListener() {
0248: public void onAttributeBeingUpdated(
0249: RefObject pModelElementBeingUpdated,
0250: String pAttributeName,
0251: Object pOldValue, Object pNewValue) {
0252: AssociationRole lReference = (AssociationRole) pModelElementBeingUpdated;
0253: String lReferencePluralName = lReference
0254: .getPluralName();
0255: if (lReferencePluralName == null)
0256: return; // Role does not have a name
0257: Entity lReferencingEntity = lReference
0258: .getReferencingEntity();
0259: if (lReferencingEntity == null)
0260: return; // Attribute is not associated with entity
0261: Domain lDomain = lReferencingEntity
0262: .getDomain();
0263: if (lDomain == null)
0264: return; // Entity is not associated with domain
0265: String lDomainName = lDomain.getName();
0266: if (lDomainName == null)
0267: return; // Domain does not have a name
0268: com.metaboss.sdlctools.models.metabossmodel.enterprisemodel.System lSystem = lDomain
0269: .getSystem();
0270: if (lSystem == null)
0271: return; // Domain is not associated with system
0272: Servicemodule lServicemodule = lSystem
0273: .findServicemodule(StylesheetImpl
0274: .getDomainSupportServicemoduleName(lDomainName));
0275: if (lServicemodule == null)
0276: return; // There is no support servicemodule yet
0277: Service lDomainSupportService = lServicemodule
0278: .findService(StylesheetImpl
0279: .getDataManagementServiceName(lDomainName));
0280: if (lDomainSupportService == null)
0281: return; // There is no domain support service yet
0282: AssociationRole lOppositeRole = lReference
0283: .getOppositeRole();
0284: // Iterate through all entities having this reference and ensure that the change is reflected
0285: {
0286: Set lAllEntitiesToConsider = new HashSet();
0287: lAllEntitiesToConsider
0288: .add(lReferencingEntity);
0289: lAllEntitiesToConsider
0290: .addAll(lReferencingEntity
0291: .getCombinedSubtypes());
0292: for (Iterator lEntityElementsIterator = lAllEntitiesToConsider
0293: .iterator(); lEntityElementsIterator
0294: .hasNext();) {
0295: Entity lEntityElement = (Entity) lEntityElementsIterator
0296: .next();
0297: String lEntityName = lEntityElement
0298: .getName();
0299: if (lEntityName == null)
0300: continue; // Entity does not have a name
0301: if (lOppositeRole != null
0302: && (AssociationRoleCardinalityEnum.ONE_TO_MANY
0303: .equals(pNewValue) || AssociationRoleCardinalityEnum.ZERO_TO_MANY
0304: .equals(pNewValue))
0305: && // lReferenc.isPlural()
0306: lOppositeRole
0307: .isPlural()
0308: && AggregationTypeEnum.AGGREGATION
0309: .equals(lOppositeRole
0310: .getAggregationType()))
0311: ensurePresent(
0312: lDomainSupportService,
0313: lReference,
0314: lEntityName,
0315: lReferencePluralName);
0316: else
0317: ensureAbsent(
0318: lDomainSupportService,
0319: lEntityName,
0320: lReferencePluralName);
0321: }
0322: }
0323: // Look at the entity at the opposite side and ensure that the change is reflected
0324: if (lOppositeRole != null) {
0325: Entity lReferencedEntity = lReference
0326: .getEntity();
0327: String lReferencedEntityName = lReferencedEntity
0328: .getName();
0329: String lOppositeRolePluralName = lOppositeRole
0330: .getName();
0331: if (lReferencedEntityName != null) {
0332: if ((AssociationRoleCardinalityEnum.ONE_TO_MANY
0333: .equals(pNewValue) || AssociationRoleCardinalityEnum.ZERO_TO_MANY
0334: .equals(pNewValue))
0335: && // lReferenc.isPlural()
0336: lOppositeRole
0337: .isPlural()
0338: && AggregationTypeEnum.AGGREGATION
0339: .equals(lReference
0340: .getAggregationType()))
0341: ensurePresent(
0342: lDomainSupportService,
0343: lOppositeRole,
0344: lReferencedEntityName,
0345: lOppositeRolePluralName);
0346: else
0347: ensureAbsent(
0348: lDomainSupportService,
0349: lReferencedEntityName,
0350: lOppositeRolePluralName);
0351: }
0352: }
0353: }
0354: });
0355: }
0356:
0357: private static final String sOperationConstraintTextBase = "A Data Management Service must have Remove Referenced Entities operation for every many-to-many Association between Entities in the corresponding Domain.";
0358: private static final String sReferencingEntityKeyInputFieldConstraintTextBase = "A Remove Referenced Entities Data Management Operation must have well formed Referencing Entity Key input parameter carrying referencing Entity identification information.";
0359: private static final String sReferencedEntityKeysInputFieldConstraintTextBase = "A Remove Referenced Entities Data Management Operation must have well formed Old Referenced Entity Keys input parameter carrying outgoing referenced Entities identification information.";
0360: private static final String sOperationInputConstraintTextBase = "A Remove Referenced Entities Data Management Operation must have well formed Input Constraints performing sanity check on the input data.";
0361: private static final String sEntityNotFoundErrorOutputMessageConstraintTextBase = "A Remove Referenced Entities Data Management Operation must have well formed Entity Not Found output message, one for each reference, which is a part of the primary key of both referencing and referenced Entities.";
0362:
0363: // This helper verifies constraints
0364: void verifyConstraints(Collection pViolations,
0365: Service pDataManagementService, AssociationRole pReference,
0366: Collection pUnclaimedOperations) {
0367: // Check if we have an operation and than just call ensurePresent
0368: Entity lReferencedEntity = pReference.getEntity();
0369: if (lReferencedEntity == null)
0370: return; // Unable to verify constraints
0371: String lReferencedEntityName = lReferencedEntity.getName();
0372: if (lReferencedEntityName == null)
0373: return; // Unable to verify constraints
0374: // Check if we have an operation and than just call ensurePresent
0375: AssociationRole lOppositeReference = pReference
0376: .getOppositeRole();
0377: Entity lReferencingEntity = lOppositeReference.getEntity();
0378: if (lReferencingEntity == null)
0379: return; // Unable to rectify properly
0380: String lReferencingEntityName = lReferencingEntity.getName();
0381: if (lReferencingEntityName == null)
0382: return; // Unable to rectify properly
0383: String lReferencePluralName = pReference.getPluralName();
0384: if (lReferencePluralName == null)
0385: return; // Unable to rectify properly
0386: // Work on the Key structure
0387: String lOperationName = suggestOperationName(
0388: lReferencingEntityName, lReferencePluralName);
0389: Operation lOperation = pDataManagementService
0390: .findOperation(lOperationName);
0391: if (lOperation == null) {
0392: if (AggregationTypeEnum.AGGREGATION
0393: .equals(lOppositeReference.getAggregationType())
0394: && pReference.isPlural()
0395: && lOppositeReference.isPlural())
0396: pViolations.add(new ConstraintViolationException(
0397: pDataManagementService, pDataManagementService
0398: .refMetaObject(),
0399: sOperationConstraintTextBase + " The '"
0400: + lOperationName
0401: + "' Operation not found."));
0402: return;
0403: }
0404: pUnclaimedOperations.remove(lOperation); // Claim the operation
0405: if (AggregationTypeEnum.AGGREGATION.equals(lOppositeReference
0406: .getAggregationType()) == false
0407: || pReference.isPlural() == false
0408: || lOppositeReference.isPlural() == false) {
0409: pViolations.add(new ConstraintViolationException(
0410: pDataManagementService, pDataManagementService
0411: .refMetaObject(),
0412: sOperationConstraintTextBase + " The '"
0413: + lOperationName
0414: + "' Operation unexpected."));
0415: return;
0416: }
0417: // Validate operation details
0418: // Input Fields - only verify that the ones that we need exist. The extra ones are allowed
0419: {
0420: // Entity key parameter
0421: {
0422: String lOperationInputFieldName = suggestEntityKeyInputParameterName(lReferencingEntityName);
0423: OperationInputField lInputField = lOperation
0424: .findInputField(lOperationInputFieldName);
0425: if (lInputField != null) {
0426: Structure lEntityKeyStructure = pDataManagementService
0427: .getServicemodule() != null ? pDataManagementService
0428: .getServicemodule()
0429: .findStructure(
0430: StylesheetImpl
0431: .getEntityKeyStructureName(lReferencingEntityName))
0432: : null;
0433: if (lEntityKeyStructure != null
0434: && lEntityKeyStructure.equals(lInputField
0435: .getStructureType()) == false)
0436: pViolations
0437: .add(new ConstraintViolationException(
0438: lInputField,
0439: lInputField.refMetaObject(),
0440: sReferencingEntityKeyInputFieldConstraintTextBase
0441: + " The '"
0442: + lOperationInputFieldName
0443: + "' input field has wrong type."));
0444: if (lInputField.isArray())
0445: pViolations
0446: .add(new ConstraintViolationException(
0447: lInputField,
0448: lInputField.refMetaObject(),
0449: sReferencingEntityKeyInputFieldConstraintTextBase
0450: + " The '"
0451: + lOperationInputFieldName
0452: + "' input field is an array, which is wrong."));
0453: } else
0454: pViolations.add(new ConstraintViolationException(
0455: lOperation, lOperation.refMetaObject(),
0456: sReferencingEntityKeyInputFieldConstraintTextBase
0457: + " The '"
0458: + lOperationInputFieldName
0459: + "' input field is missing."));
0460: }
0461: // Reference key parameter
0462: String lReferenceName = pReference.getName();
0463: if (lReferenceName != null) {
0464: String lOperationInputFieldName = suggestReferenceKeysInputParameterName(lReferenceName);
0465: OperationInputField lInputField = lOperation
0466: .findInputField(lOperationInputFieldName);
0467: if (lInputField != null) {
0468: if (lReferencedEntityName != null) {
0469: Structure lEntityKeyStructure = pDataManagementService
0470: .getServicemodule() != null ? pDataManagementService
0471: .getServicemodule()
0472: .findStructure(
0473: StylesheetImpl
0474: .getEntityKeyStructureName(lReferencedEntityName))
0475: : null;
0476: if (lEntityKeyStructure != null
0477: && lEntityKeyStructure
0478: .equals(lInputField
0479: .getStructureType()) == false)
0480: pViolations
0481: .add(new ConstraintViolationException(
0482: lInputField,
0483: lInputField.refMetaObject(),
0484: sReferencedEntityKeysInputFieldConstraintTextBase
0485: + " The '"
0486: + lOperationInputFieldName
0487: + "' input field has wrong type."));
0488: }
0489: if (!lInputField.isArray())
0490: pViolations
0491: .add(new ConstraintViolationException(
0492: lInputField,
0493: lInputField.refMetaObject(),
0494: sReferencedEntityKeysInputFieldConstraintTextBase
0495: + " The '"
0496: + lOperationInputFieldName
0497: + "' input field is not an array, which is wrong."));
0498: } else
0499: pViolations.add(new ConstraintViolationException(
0500: lOperation, lOperation.refMetaObject(),
0501: sReferencedEntityKeysInputFieldConstraintTextBase
0502: + " The '"
0503: + lOperationInputFieldName
0504: + "' input field is missing."));
0505: }
0506: }
0507: // Input constraints - only verify that the ones that we need exist. The extra ones are allowed
0508: {
0509: // Work on the entity key validation constraint.
0510: {
0511: String lEntityKeyInputFieldName = suggestEntityKeyInputParameterName(lReferencingEntityName);
0512: String lConstraintName = lEntityKeyInputFieldName
0513: + "FieldPresenceConstraint";
0514: ModelElementConstraint lModelElementConstraint = lOperation
0515: .findInputConstraint(lConstraintName);
0516: if (lModelElementConstraint == null)
0517: pViolations
0518: .add(new ConstraintViolationException(
0519: lOperation,
0520: lOperation.refMetaObject(),
0521: sOperationInputConstraintTextBase
0522: + " The '"
0523: + lConstraintName
0524: + "' Input Constraint is missing."));
0525: }
0526: // Work on the reference constraint
0527: // Until refeence does not have a name we can not build the OCL expression
0528: String lReferenceName = pReference.getName();
0529: if (lReferenceName != null) {
0530: // Build OCL expression
0531: String lReferenceKeysInputFieldName = suggestReferenceKeysInputParameterName(lReferenceName);
0532: String lConstraintName = lReferenceKeysInputFieldName
0533: + "FieldPresenceConstraint";
0534: ModelElementConstraint lModelElementConstraint = lOperation
0535: .findInputConstraint(lConstraintName);
0536: if (lModelElementConstraint == null)
0537: pViolations
0538: .add(new ConstraintViolationException(
0539: lOperation,
0540: lOperation.refMetaObject(),
0541: sOperationInputConstraintTextBase
0542: + " The '"
0543: + lConstraintName
0544: + "' Input Constraint is missing."));
0545: }
0546: }
0547: // Output Fields - only verify that the ones that we need exist. The extra ones are allowed
0548: {
0549: // No output fields yet
0550: }
0551: // Output Messages - only verify that the ones that we need exist. The extra ones are allowed
0552: {
0553: // This method loads instances of the referencing entity and referenced entities
0554: // all of them have a chance not to be found. We need to add relevant output mesages in the output specification
0555: Set lEntitiesWhichMayBeNotFoundWhenInvokingOperation = new HashSet();
0556: lEntitiesWhichMayBeNotFoundWhenInvokingOperation
0557: .add(lReferencingEntity);
0558: Util.collectEntitiesWhichMayBeNotFoundWhenLoadingInstance(
0559: lReferencingEntity,
0560: lEntitiesWhichMayBeNotFoundWhenInvokingOperation);
0561: lEntitiesWhichMayBeNotFoundWhenInvokingOperation
0562: .add(lReferencedEntity);
0563: Util.collectEntitiesWhichMayBeNotFoundWhenLoadingInstance(
0564: lReferencedEntity,
0565: lEntitiesWhichMayBeNotFoundWhenInvokingOperation);
0566:
0567: for (Iterator lEntitiesWhichMayBeNotFoundWhenInvokingOperationIterator = lEntitiesWhichMayBeNotFoundWhenInvokingOperation
0568: .iterator(); lEntitiesWhichMayBeNotFoundWhenInvokingOperationIterator
0569: .hasNext();) {
0570: Entity lEntityElement = (Entity) lEntitiesWhichMayBeNotFoundWhenInvokingOperationIterator
0571: .next();
0572: String lEntityElementName = lEntityElement.getName();
0573: if (lEntityElementName == null)
0574: continue;
0575: String lOperationOutputMessageName = StylesheetImpl
0576: .getEntityNotFoundOperationOutputMessageName(lEntityElementName);
0577: OperationOutputMessage lOutputMessage = lOperation
0578: .findOutputMessage(lOperationOutputMessageName);
0579: if (lOutputMessage != null) {
0580: Message lEntityNotFoundMessage = pDataManagementService
0581: .getServicemodule() != null ? pDataManagementService
0582: .getServicemodule()
0583: .findMessage(
0584: StylesheetImpl
0585: .getEntityInstanceNotFoundMessageName(lEntityElementName))
0586: : null;
0587: if (lEntityNotFoundMessage != null
0588: && lEntityNotFoundMessage
0589: .equals(lOutputMessage
0590: .getMessageType()) == false)
0591: pViolations
0592: .add(new ConstraintViolationException(
0593: lOutputMessage,
0594: lOutputMessage.refMetaObject(),
0595: sEntityNotFoundErrorOutputMessageConstraintTextBase
0596: + " The '"
0597: + lOperationOutputMessageName
0598: + "' output message has wrong type."));
0599: if (lOutputMessage.isArray())
0600: pViolations
0601: .add(new ConstraintViolationException(
0602: lOutputMessage,
0603: lOutputMessage.refMetaObject(),
0604: sEntityNotFoundErrorOutputMessageConstraintTextBase
0605: + " The '"
0606: + lOperationOutputMessageName
0607: + "' output message is an array, which is wrong."));
0608: } else
0609: pViolations.add(new ConstraintViolationException(
0610: lOperation, lOperation.refMetaObject(),
0611: sEntityNotFoundErrorOutputMessageConstraintTextBase
0612: + " The '"
0613: + lOperationOutputMessageName
0614: + "' output message is missing."));
0615: }
0616: }
0617: }
0618:
0619: // This helper is doing everything necessary to rectify errors reported in verifyConstraints()
0620: void rectifyModel(Service pDataManagementService,
0621: AssociationRole pReference, Collection pUnclaimedOperations) {
0622: // Check if we have an operation and than just call ensurePresent
0623: AssociationRole lOppositeReference = pReference
0624: .getOppositeRole();
0625: Entity lReferencingEntity = lOppositeReference.getEntity();
0626: if (lReferencingEntity == null)
0627: return; // Unable to rectify properly
0628: String lReferencingEntityName = lReferencingEntity.getName();
0629: if (lReferencingEntityName == null)
0630: return; // Unable to rectify properly
0631: String lReferencePluralName = pReference.getPluralName();
0632: if (lReferencePluralName == null)
0633: return; // Unable to rectify properly
0634: String lOperationName = suggestOperationName(
0635: lReferencingEntityName, lReferencePluralName);
0636: Operation lOperation = pDataManagementService
0637: .findOperation(lOperationName);
0638: if (lOperation != null)
0639: pUnclaimedOperations.remove(lOperation); // Claim the operation
0640: // We are after aggregation side of the many to many associations
0641: if (AggregationTypeEnum.AGGREGATION.equals(lOppositeReference
0642: .getAggregationType())
0643: && pReference.isPlural()
0644: && lOppositeReference.isPlural())
0645: ensurePresent(pDataManagementService, pReference,
0646: lReferencingEntityName, lReferencePluralName);
0647: else
0648: ensureAbsent(pDataManagementService,
0649: lReferencingEntityName, lReferencePluralName);
0650: }
0651:
0652: // This helper renames and ensures that the element is present
0653: void ensureRenamedPresent(Service pDataManagementService,
0654: AssociationRole pReference, String pOldEntityName,
0655: String pNewEntityName, String pOldReferencePluralName,
0656: String pNewReferencePluralName) {
0657: // Note that this method only deals with renaming and than calls the ensure present method
0658: String lOldOperationName = suggestOperationName(pOldEntityName,
0659: pOldReferencePluralName);
0660: Operation lOldOperation = pDataManagementService
0661: .findOperation(lOldOperationName);
0662: String lNewOperationName = suggestOperationName(pNewEntityName,
0663: pNewReferencePluralName);
0664: Operation lNewOperation = pDataManagementService
0665: .findOperation(lNewOperationName);
0666: // Be relaxed here - allow for all sorts of mishaps
0667: if (lOldOperation != null) {
0668: if (lNewOperation != null) {
0669: // New and old structures are present - just delete the old one
0670: lOldOperation.refDelete();
0671: } else {
0672: // Old structure is present - new one is not - rename
0673: lOldOperation.setName(lNewOperationName);
0674: }
0675: }
0676: // Call the ensure present bit
0677: ensurePresent(pDataManagementService, pReference,
0678: pNewEntityName, pNewReferencePluralName);
0679: }
0680:
0681: // This helper makes sure that the version id attribute is present in the details structure
0682: void ensurePresent(Service pDataManagementService,
0683: AssociationRole pReference, String pReferencingEntityName,
0684: String pReferencePluralName) {
0685: Entity lReferencedEntity = pReference.getEntity();
0686: String lReferencedEntityName = lReferencedEntity != null ? lReferencedEntity
0687: .getName()
0688: : null;
0689: AssociationRole lOppositeReference = pReference
0690: .getOppositeRole();
0691: Entity lReferencingEntity = lOppositeReference.getEntity();
0692: // Work on the servicemodule
0693: String lOperationName = suggestOperationName(
0694: pReferencingEntityName, pReferencePluralName);
0695: Operation lOperation = pDataManagementService
0696: .findOperation(lOperationName);
0697: if (lOperation == null) {
0698: lOperation = mModelAssistantImpl.mOperationClass
0699: .createOperation();
0700: lOperation.setService(pDataManagementService);
0701: lOperation.setName(lOperationName);
0702: }
0703: lOperation.setDescription(suggestOperationDescription(
0704: pReferencingEntityName, pReferencePluralName));
0705: lOperation.setTransactionPolicy(TransactionPolicyEnum.REQUIRED);
0706: lOperation.setQuery(false);
0707: // Input Fields
0708: {
0709: Collection lOperationInputFields = lOperation
0710: .getInputFields();
0711: List lUnprocessedInputFields = new ArrayList();
0712: lUnprocessedInputFields.addAll(lOperationInputFields);
0713: // Add entity key parameter
0714: {
0715: String lOperationInputFieldName = suggestEntityKeyInputParameterName(pReferencingEntityName);
0716: OperationInputField lInputField = lOperation
0717: .findInputField(lOperationInputFieldName);
0718: if (lInputField == null) {
0719: lInputField = mModelAssistantImpl.mOperationInputFieldClass
0720: .createOperationInputField();
0721: lInputField.setName(lOperationInputFieldName);
0722: lInputField.setOperation(lOperation);
0723: } else {
0724: lUnprocessedInputFields.remove(lInputField);
0725: }
0726: lInputField
0727: .setDescription(suggestEntityKeyInputParameterDescription(pReferencingEntityName));
0728: lInputField.setArray(false);
0729: lInputField.setDataType(null);
0730: Structure lEntityKeyStructure = pDataManagementService
0731: .getServicemodule() != null ? pDataManagementService
0732: .getServicemodule()
0733: .findStructure(
0734: StylesheetImpl
0735: .getEntityKeyStructureName(pReferencingEntityName))
0736: : null;
0737: lInputField.setStructureType(lEntityKeyStructure);
0738: }
0739: // Add reference key parameter
0740: String lReferenceName = pReference.getName();
0741: if (lReferenceName != null) {
0742: String lOperationInputFieldName = suggestReferenceKeysInputParameterName(lReferenceName);
0743: OperationInputField lInputField = lOperation
0744: .findInputField(lOperationInputFieldName);
0745: if (lInputField == null) {
0746: lInputField = mModelAssistantImpl.mOperationInputFieldClass
0747: .createOperationInputField();
0748: lInputField.setName(lOperationInputFieldName);
0749: lInputField.setOperation(lOperation);
0750: } else {
0751: lUnprocessedInputFields.remove(lInputField);
0752: }
0753: lInputField
0754: .setDescription(suggestReferenceKeysInputParameterDescription(pReferencePluralName));
0755: lInputField.setArray(true);
0756: lInputField.setDataType(null);
0757:
0758: Structure lEntityKeyStructure = null;
0759: Servicemodule lServicemodule = pDataManagementService
0760: .getServicemodule();
0761: if (lServicemodule != null
0762: && lReferencedEntityName != null) {
0763: lEntityKeyStructure = lServicemodule
0764: .findStructure(StylesheetImpl
0765: .getEntityKeyStructureName(lReferencedEntityName));
0766: }
0767: lInputField.setStructureType(lEntityKeyStructure);
0768: }
0769:
0770: // Delete all input fields left
0771: for (Iterator lUnprocessedInputFieldsIterator = lUnprocessedInputFields
0772: .iterator(); lUnprocessedInputFieldsIterator
0773: .hasNext();) {
0774: OperationInputField lInputField = (OperationInputField) lUnprocessedInputFieldsIterator
0775: .next();
0776: if (!lInputField.isDerived())
0777: lInputField.refDelete();
0778: }
0779: }
0780: // Input constraints
0781: {
0782: // Copy aside the collection of the constraints, so we can delete the unused ones
0783: Collection lUnclaimedConstraints = new ArrayList();
0784: lUnclaimedConstraints.addAll(lOperation
0785: .getInputConstraints());
0786: // Work on the entity key validation constraint.
0787: {
0788: String lEntityKeyInputFieldName = suggestEntityKeyInputParameterName(pReferencingEntityName);
0789: String lEntityKeyOCLFieldName = lEntityKeyInputFieldName
0790: .substring(0, 1).toLowerCase()
0791: + lEntityKeyInputFieldName.substring(1);
0792: String lConstraintName = lEntityKeyInputFieldName
0793: + "FieldPresenceConstraint";
0794: ModelElementConstraint lModelElementConstraint = lOperation
0795: .findInputConstraint(lConstraintName);
0796: if (lModelElementConstraint == null) {
0797: lModelElementConstraint = mModelAssistantImpl.mModelElementConstraintClass
0798: .createModelElementConstraint();
0799: lModelElementConstraint.setName(lConstraintName);
0800: lOperation.getInputConstraints().add(
0801: lModelElementConstraint);
0802: } else {
0803: // Claim the field
0804: lUnclaimedConstraints
0805: .remove(lModelElementConstraint);
0806: }
0807: lModelElementConstraint
0808: .setDescription("Verifies that the "
0809: + lEntityKeyInputFieldName
0810: + " input field is not empty in the operation input");
0811: lModelElementConstraint.setDefaultErrorText("The '"
0812: + lEntityKeyInputFieldName
0813: + "' input field must not be empty.");
0814: lModelElementConstraint.setOclExpression("not "
0815: + lEntityKeyOCLFieldName + ".oclIsUndefined()");
0816: }
0817: // Work on the reference constraint
0818: // Until refeence does not have a name we can not build the OCL expression
0819: if (pReference.getName() != null) {
0820: // Build OCL expression
0821: String lReferenceKeysInputFieldName = suggestReferenceKeysInputParameterName(pReference
0822: .getName());
0823: String lReferenceKeysOCLFieldName = lReferenceKeysInputFieldName
0824: .substring(0, 1).toLowerCase()
0825: + lReferenceKeysInputFieldName.substring(1);
0826: String lConstraintName = lReferenceKeysInputFieldName
0827: + "FieldPresenceConstraint";
0828: ModelElementConstraint lModelElementConstraint = lOperation
0829: .findInputConstraint(lConstraintName);
0830: if (lModelElementConstraint == null) {
0831: lModelElementConstraint = mModelAssistantImpl.mModelElementConstraintClass
0832: .createModelElementConstraint();
0833: lModelElementConstraint.setName(lConstraintName);
0834: lOperation.getInputConstraints().add(
0835: lModelElementConstraint);
0836: } else {
0837: // Claim the field
0838: lUnclaimedConstraints
0839: .remove(lModelElementConstraint);
0840: }
0841: lModelElementConstraint
0842: .setDescription("Verifies that the "
0843: + lReferenceKeysInputFieldName
0844: + " input field has at least one element in the operation input");
0845: lModelElementConstraint
0846: .setDefaultErrorText("The '"
0847: + lReferenceKeysInputFieldName
0848: + "' input field must contain one or more non empty elements.");
0849: lModelElementConstraint
0850: .setOclExpression(lReferenceKeysOCLFieldName
0851: + "->size > 0 and "
0852: + lReferenceKeysOCLFieldName
0853: + "->forAll(not oclIsUndefined())");
0854: }
0855: // Remove unclaimed constraints
0856: for (Iterator lUnclaimedConstraintsIterator = lUnclaimedConstraints
0857: .iterator(); lUnclaimedConstraintsIterator
0858: .hasNext();) {
0859: ModelElementConstraint lUnclaimedConstraint = (ModelElementConstraint) lUnclaimedConstraintsIterator
0860: .next();
0861: if (!lUnclaimedConstraint.isDerived())
0862: lUnclaimedConstraint.refDelete();
0863: }
0864: }
0865: // Output Fields
0866: {
0867: Collection lOperationOutputFields = lOperation
0868: .getOutputFields();
0869: List lUnprocessedOutputFields = new ArrayList();
0870: lUnprocessedOutputFields.addAll(lOperationOutputFields);
0871:
0872: // No output fields
0873:
0874: // Delete all output fields left
0875: for (Iterator lUnprocessedOutputFieldsIterator = lUnprocessedOutputFields
0876: .iterator(); lUnprocessedOutputFieldsIterator
0877: .hasNext();) {
0878: OperationOutputField lOutputField = (OperationOutputField) lUnprocessedOutputFieldsIterator
0879: .next();
0880: if (!lOutputField.isDerived())
0881: lOutputField.refDelete();
0882: }
0883: }
0884: // Output Messages
0885: {
0886: Collection lOperationOutputMessages = lOperation
0887: .getOutputMessages();
0888: List lUnprocessedOutputMessages = new ArrayList();
0889: lUnprocessedOutputMessages.addAll(lOperationOutputMessages);
0890:
0891: // Output Messages - only verify that the ones that we need exist. The extra ones are allowed
0892: {
0893: // This method loads instances of the referencing entity and referenced entities
0894: // all of them have a chance not to be found. We need to add relevant output mesages in the output specification
0895: Set lEntitiesWhichMayBeNotFoundWhenInvokingOperation = new HashSet();
0896: lEntitiesWhichMayBeNotFoundWhenInvokingOperation
0897: .add(lReferencingEntity);
0898: Util
0899: .collectEntitiesWhichMayBeNotFoundWhenLoadingInstance(
0900: lReferencingEntity,
0901: lEntitiesWhichMayBeNotFoundWhenInvokingOperation);
0902: lEntitiesWhichMayBeNotFoundWhenInvokingOperation
0903: .add(lReferencedEntity);
0904: Util
0905: .collectEntitiesWhichMayBeNotFoundWhenLoadingInstance(
0906: lReferencedEntity,
0907: lEntitiesWhichMayBeNotFoundWhenInvokingOperation);
0908:
0909: for (Iterator lEntitiesWhichMayBeNotFoundWhenInvokingOperationIterator = lEntitiesWhichMayBeNotFoundWhenInvokingOperation
0910: .iterator(); lEntitiesWhichMayBeNotFoundWhenInvokingOperationIterator
0911: .hasNext();) {
0912: Entity lEntityElement = (Entity) lEntitiesWhichMayBeNotFoundWhenInvokingOperationIterator
0913: .next();
0914: // We need to use entity name parameter for the entity which is passed as a parameter.
0915: String lEntityElementName = lEntityElement
0916: .equals(lReferencingEntity) ? pReferencingEntityName
0917: : lEntityElement.getName();
0918: if (lEntityElementName == null)
0919: continue;
0920: String lOperationOutputMessageName = StylesheetImpl
0921: .getEntityNotFoundOperationOutputMessageName(lEntityElementName);
0922: OperationOutputMessage lOutputMessage = lOperation
0923: .findOutputMessage(lOperationOutputMessageName);
0924: if (lOutputMessage == null) {
0925: lOutputMessage = mModelAssistantImpl.mOperationOutputMessageClass
0926: .createOperationOutputMessage();
0927: lOutputMessage
0928: .setName(lOperationOutputMessageName);
0929: lOutputMessage.setOperation(lOperation);
0930: } else {
0931: lUnprocessedOutputMessages
0932: .remove(lOutputMessage);
0933: }
0934: lOutputMessage
0935: .setDescription(StylesheetImpl
0936: .getEntityNotFoundOperationOutputMessageDescription(lEntityElementName));
0937: lOutputMessage.setArray(false);
0938: Message lEntityNotFoundMessage = pDataManagementService
0939: .getServicemodule() != null ? pDataManagementService
0940: .getServicemodule()
0941: .findMessage(
0942: StylesheetImpl
0943: .getEntityInstanceNotFoundMessageName(lEntityElementName))
0944: : null;
0945: lOutputMessage
0946: .setMessageType(lEntityNotFoundMessage);
0947: }
0948: }
0949: // Delete all output messages left
0950: for (Iterator lUnprocessedOutputMessagesIterator = lUnprocessedOutputMessages
0951: .iterator(); lUnprocessedOutputMessagesIterator
0952: .hasNext();) {
0953: OperationOutputMessage lOutputMessage = (OperationOutputMessage) lUnprocessedOutputMessagesIterator
0954: .next();
0955: if (!lOutputMessage.isDerived())
0956: lOutputMessage.refDelete();
0957: }
0958: }
0959: }
0960:
0961: // This helper makes sure that the version id attribute is absent in the details structure
0962: void ensureAbsent(Service pDataManagementService,
0963: String pEntityName, String pReferencePluralName) {
0964: // Work on the details structure
0965: Operation lOperation = pDataManagementService
0966: .findOperation(suggestOperationName(pEntityName,
0967: pReferencePluralName));
0968: if (lOperation != null)
0969: lOperation.refDelete();
0970: }
0971:
0972: // Helper. Returns the message name
0973: private static String suggestOperationName(String pEntityName,
0974: String pReferencePluralName) {
0975: // Use normalised name here
0976: return "remove"
0977: + StringUtils.suggestName(pReferencePluralName, true,
0978: false) + "From"
0979: + StringUtils.suggestName(pEntityName, true, false);
0980: }
0981:
0982: // Helper. Returns the message description
0983: private static String suggestOperationDescription(
0984: String pEntityName, String pReferencePluralName) {
0985: // Use name 'as is' here
0986: return "Removes one or more " + pReferencePluralName
0987: + " from the specified " + pEntityName + " instance.";
0988: }
0989:
0990: // Helper. Returns the name
0991: private static String suggestEntityKeyInputParameterName(
0992: String pEntityName) {
0993: return StringUtils.suggestName(pEntityName, true, false)
0994: + "Key";
0995: }
0996:
0997: // Helper. Returns the description
0998: private static String suggestEntityKeyInputParameterDescription(
0999: String pEntityName) {
1000: // Use name 'as is' here
1001: return "The unique key identifying the " + pEntityName
1002: + " to be edited.";
1003: }
1004:
1005: // Helper. Returns the name
1006: private static String suggestReferenceKeysInputParameterName(
1007: String pReferenceName) {
1008: return StringUtils.suggestName(pReferenceName, true, false)
1009: + "Keys";
1010: }
1011:
1012: // Helper. Returns the description
1013: private static String suggestReferenceKeysInputParameterDescription(
1014: String pReferencePluralName) {
1015: // Use name 'as is' here
1016: return "The array of unique keys identifying "
1017: + pReferencePluralName + " to be removed.";
1018: }
1019: }
|