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 TargetAddReferencedEntityOperationHelper {
0046: private ModelAssistantImpl mModelAssistantImpl;
0047:
0048: TargetAddReferencedEntityOperationHelper(
0049: ModelAssistantImpl pModelAssistantImpl) {
0050: mModelAssistantImpl = pModelAssistantImpl;
0051:
0052: // Add entity Name attribute change listener
0053: mModelAssistantImpl
0054: .addAttributeChangeListener(
0055: Entity.class,
0056: "Name",
0057: new ModelAssistantImpl.ModelElementAttributeChangeListener() {
0058: public void onAttributeBeingUpdated(
0059: RefObject pModelElementBeingUpdated,
0060: String pAttributeName,
0061: Object pOldValue, Object pNewValue) {
0062: Entity lEntity = (Entity) pModelElementBeingUpdated;
0063: Domain lDomain = lEntity.getDomain();
0064: if (lDomain == null)
0065: return; // Entity is not associated with domain
0066: String lDomainName = lDomain.getName();
0067: if (lDomainName == null)
0068: return; // Domain does not have a name
0069: com.metaboss.sdlctools.models.metabossmodel.enterprisemodel.System lSystem = lDomain
0070: .getSystem();
0071: if (lSystem == null)
0072: return; // Domain is not associated with system
0073: Servicemodule lServicemodule = lSystem
0074: .findServicemodule(StylesheetImpl
0075: .getDomainSupportServicemoduleName(lDomainName));
0076: if (lServicemodule == null)
0077: return; // There is no support servicemodule yet
0078: Service lDomainSupportService = lServicemodule
0079: .findService(StylesheetImpl
0080: .getDataManagementServiceName(lDomainName));
0081: if (lDomainSupportService == null)
0082: return; // There is no domain support service yet
0083: // Iterate through all references for this entity and ensure that the change is reflected
0084: // Iterate through references and ensure that the name change is accounted for
0085: for (Iterator lEntityReferencesIterator = lEntity
0086: .getCombinedReferences()
0087: .iterator(); lEntityReferencesIterator
0088: .hasNext();) {
0089: AssociationRole lReference = (AssociationRole) lEntityReferencesIterator
0090: .next();
0091: String lReferencePluralName = lReference
0092: .getPluralName();
0093: if (lReferencePluralName == null)
0094: continue; // Reference does not have a plural name yet
0095: if (pNewValue == null) {
0096: // Only old value is known - ensure that the element is deleted
0097: ensureAbsent(
0098: lDomainSupportService,
0099: (String) pOldValue,
0100: lReferencePluralName);
0101: } else {
0102: // New value is known - analyse the criteria and deal with the element accordingly
0103: AssociationRole lOppositeRole = lReference
0104: .getOppositeRole();
0105: if (lOppositeRole != null
0106: && lReference
0107: .isPlural()
0108: && lOppositeRole
0109: .isPlural()
0110: && AggregationTypeEnum.AGGREGATION
0111: .equals(lOppositeRole
0112: .getAggregationType())) {
0113: // The element must be present - rename or create
0114: if (pOldValue != null)
0115: ensureRenamedPresent(
0116: lDomainSupportService,
0117: lReference,
0118: (String) pOldValue,
0119: (String) pNewValue,
0120: lReferencePluralName,
0121: lReferencePluralName);
0122: else
0123: ensurePresent(
0124: lDomainSupportService,
0125: lReference,
0126: (String) pNewValue,
0127: lReferencePluralName);
0128: } else {
0129: // The element must be absent - delete
0130: ensureAbsent(
0131: lDomainSupportService,
0132: (String) pNewValue,
0133: lReferencePluralName);
0134: if (pOldValue != null)
0135: ensureAbsent(
0136: lDomainSupportService,
0137: (String) pOldValue,
0138: lReferencePluralName);
0139: }
0140: }
0141: }
0142: }
0143: });
0144:
0145: // Add reference pluralName attribute change listener
0146: mModelAssistantImpl
0147: .addAttributeChangeListener(
0148: AssociationRole.class,
0149: "pluralName",
0150: new ModelAssistantImpl.ModelElementAttributeChangeListener() {
0151: public void onAttributeBeingUpdated(
0152: RefObject pModelElementBeingUpdated,
0153: String pAttributeName,
0154: Object pOldValue, Object pNewValue) {
0155: AssociationRole lReference = (AssociationRole) pModelElementBeingUpdated;
0156: Entity lEntity = lReference
0157: .getReferencingEntity();
0158: if (lEntity == null)
0159: return; // Attribute is not associated with entity
0160: Domain lDomain = lEntity.getDomain();
0161: if (lDomain == null)
0162: return; // Entity is not associated with domain
0163: String lDomainName = lDomain.getName();
0164: if (lDomainName == null)
0165: return; // Domain does not have a name
0166: com.metaboss.sdlctools.models.metabossmodel.enterprisemodel.System lSystem = lDomain
0167: .getSystem();
0168: if (lSystem == null)
0169: return; // Domain is not associated with system
0170: Servicemodule lServicemodule = lSystem
0171: .findServicemodule(StylesheetImpl
0172: .getDomainSupportServicemoduleName(lDomainName));
0173: if (lServicemodule == null)
0174: return; // There is no support servicemodule yet
0175: Service lDomainSupportService = lServicemodule
0176: .findService(StylesheetImpl
0177: .getDataManagementServiceName(lDomainName));
0178: if (lDomainSupportService == null)
0179: return; // There is no domain support service yet
0180: AssociationRole lOppositeRole = lReference
0181: .getOppositeRole();
0182: // Iterate through all entities containing this reference and ensure that the change is reflected
0183: Set lAllEntitiesToConsider = new HashSet();
0184: lAllEntitiesToConsider.add(lEntity);
0185: lAllEntitiesToConsider.addAll(lEntity
0186: .getCombinedSubtypes());
0187: for (Iterator lEntityElementsIterator = lAllEntitiesToConsider
0188: .iterator(); lEntityElementsIterator
0189: .hasNext();) {
0190: Entity lEntityElement = (Entity) lEntityElementsIterator
0191: .next();
0192: String lEntityName = lEntityElement
0193: .getName();
0194: if (lEntityName == null)
0195: continue; // Entity does not have a name
0196: if (pNewValue == null) {
0197: // Only old value is known - ensure that the element is deleted
0198: ensureAbsent(
0199: lDomainSupportService,
0200: lEntityName,
0201: (String) pOldValue);
0202: } else {
0203: // New value is known - analyse the criteria and deal with the element accordingly
0204: if (lOppositeRole != null
0205: && lReference
0206: .isPlural()
0207: && lOppositeRole
0208: .isPlural()
0209: && AggregationTypeEnum.AGGREGATION
0210: .equals(lOppositeRole
0211: .getAggregationType())) {
0212: // The element must be present - rename or create
0213: if (pOldValue != null)
0214: ensureRenamedPresent(
0215: lDomainSupportService,
0216: lReference,
0217: lEntityName,
0218: lEntityName,
0219: (String) pOldValue,
0220: (String) pNewValue);
0221: else
0222: ensurePresent(
0223: lDomainSupportService,
0224: lReference,
0225: lEntityName,
0226: (String) pNewValue);
0227: } else {
0228: // The element must be absent - delete
0229: ensureAbsent(
0230: lDomainSupportService,
0231: lEntityName,
0232: (String) pNewValue);
0233: if (pOldValue != null)
0234: ensureAbsent(
0235: lDomainSupportService,
0236: lEntityName,
0237: (String) pOldValue);
0238: }
0239: }
0240: }
0241: }
0242: });
0243:
0244: // Add reference cardinality attribute change listener
0245: mModelAssistantImpl
0246: .addAttributeChangeListener(
0247: AssociationRole.class,
0248: "cardinality",
0249: new ModelAssistantImpl.ModelElementAttributeChangeListener() {
0250: public void onAttributeBeingUpdated(
0251: RefObject pModelElementBeingUpdated,
0252: String pAttributeName,
0253: Object pOldValue, Object pNewValue) {
0254: AssociationRole lReference = (AssociationRole) pModelElementBeingUpdated;
0255: String lReferencePluralName = lReference
0256: .getPluralName();
0257: if (lReferencePluralName == null)
0258: return; // Role does not have a name
0259: Entity lReferencingEntity = lReference
0260: .getReferencingEntity();
0261: if (lReferencingEntity == null)
0262: return; // Attribute is not associated with entity
0263: Domain lDomain = lReferencingEntity
0264: .getDomain();
0265: if (lDomain == null)
0266: return; // Entity is not associated with domain
0267: String lDomainName = lDomain.getName();
0268: if (lDomainName == null)
0269: return; // Domain does not have a name
0270: com.metaboss.sdlctools.models.metabossmodel.enterprisemodel.System lSystem = lDomain
0271: .getSystem();
0272: if (lSystem == null)
0273: return; // Domain is not associated with system
0274: Servicemodule lServicemodule = lSystem
0275: .findServicemodule(StylesheetImpl
0276: .getDomainSupportServicemoduleName(lDomainName));
0277: if (lServicemodule == null)
0278: return; // There is no support servicemodule yet
0279: Service lDomainSupportService = lServicemodule
0280: .findService(StylesheetImpl
0281: .getDataManagementServiceName(lDomainName));
0282: if (lDomainSupportService == null)
0283: return; // There is no domain support service yet
0284: AssociationRole lOppositeRole = lReference
0285: .getOppositeRole();
0286: // Iterate through all entities having this reference and ensure that the change is reflected
0287: {
0288: Set lAllEntitiesToConsider = new HashSet();
0289: lAllEntitiesToConsider
0290: .add(lReferencingEntity);
0291: lAllEntitiesToConsider
0292: .addAll(lReferencingEntity
0293: .getCombinedSubtypes());
0294: for (Iterator lEntityElementsIterator = lAllEntitiesToConsider
0295: .iterator(); lEntityElementsIterator
0296: .hasNext();) {
0297: Entity lEntityElement = (Entity) lEntityElementsIterator
0298: .next();
0299: String lEntityName = lEntityElement
0300: .getName();
0301: if (lEntityName == null)
0302: continue; // Entity does not have a name
0303: if (lOppositeRole != null
0304: && (AssociationRoleCardinalityEnum.ONE_TO_MANY
0305: .equals(pNewValue) || AssociationRoleCardinalityEnum.ZERO_TO_MANY
0306: .equals(pNewValue))
0307: && // lReferenc.isPlural()
0308: lOppositeRole
0309: .isPlural()
0310: && AggregationTypeEnum.AGGREGATION
0311: .equals(lOppositeRole
0312: .getAggregationType()))
0313: ensurePresent(
0314: lDomainSupportService,
0315: lReference,
0316: lEntityName,
0317: lReferencePluralName);
0318: else
0319: ensureAbsent(
0320: lDomainSupportService,
0321: lEntityName,
0322: lReferencePluralName);
0323: }
0324: }
0325: // Look at the entity at the opposite side and ensure that the change is reflected
0326: if (lOppositeRole != null) {
0327: Entity lReferencedEntity = lReference
0328: .getEntity();
0329: String lReferencedEntityName = lReferencedEntity
0330: .getName();
0331: String lOppositeRolePluralName = lOppositeRole
0332: .getName();
0333: if (lReferencedEntityName != null) {
0334: if ((AssociationRoleCardinalityEnum.ONE_TO_MANY
0335: .equals(pNewValue) || AssociationRoleCardinalityEnum.ZERO_TO_MANY
0336: .equals(pNewValue))
0337: && // lReferenc.isPlural()
0338: lOppositeRole
0339: .isPlural()
0340: && AggregationTypeEnum.AGGREGATION
0341: .equals(lReference
0342: .getAggregationType()))
0343: ensurePresent(
0344: lDomainSupportService,
0345: lOppositeRole,
0346: lReferencedEntityName,
0347: lOppositeRolePluralName);
0348: else
0349: ensureAbsent(
0350: lDomainSupportService,
0351: lReferencedEntityName,
0352: lOppositeRolePluralName);
0353: }
0354: }
0355: }
0356: });
0357: }
0358:
0359: private static final String sOperationConstraintTextBase = "A Data Management Service must have Add Referenced Entities operation for every many-to-many Association between Entities in the corresponding Domain.";
0360: private static final String sReferencingEntityKeyInputFieldConstraintTextBase = "An Add Referenced Entities Data Management Operation must have well formed Referencing Entity Key input parameter carrying referencing Entity identification information.";
0361: private static final String sReferencedEntityKeysInputFieldConstraintTextBase = "An Add Referenced Entities Data Management Operation must have well formed New Referenced Entity Keys input parameter carrying new referenced Entities identification information.";
0362: private static final String sOperationInputConstraintTextBase = "An Add Referenced Entities Data Management Operation must have well formed Input Constraints performing sanity check on the input data.";
0363: private static final String sEntityNotFoundErrorOutputMessageConstraintTextBase = "An Add 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.";
0364:
0365: // This helper verifies constraints
0366: void verifyConstraints(Collection pViolations,
0367: Service pDataManagementService, AssociationRole pReference,
0368: Collection pUnclaimedOperations) {
0369: // Check if we have an operation and than just call ensurePresent
0370: Entity lReferencedEntity = pReference.getEntity();
0371: if (lReferencedEntity == null)
0372: return; // Unable to verify constraints
0373: String lReferencedEntityName = lReferencedEntity.getName();
0374: if (lReferencedEntityName == null)
0375: return; // Unable to verify constraints
0376: AssociationRole lOppositeReference = pReference
0377: .getOppositeRole();
0378: Entity lReferencingEntity = lOppositeReference.getEntity();
0379: if (lReferencingEntity == null)
0380: return; // Unable to verify constraints
0381: String lReferencingEntityName = lReferencingEntity.getName();
0382: if (lReferencingEntityName == null)
0383: return; // Unable to verify constraints
0384: String lReferencePluralName = pReference.getPluralName();
0385: if (lReferencePluralName == null)
0386: return; // Unable to verify constraints
0387:
0388: // Work on the Key structure
0389: String lOperationName = suggestOperationName(
0390: lReferencingEntityName, lReferencePluralName);
0391: Operation lOperation = pDataManagementService
0392: .findOperation(lOperationName);
0393: if (lOperation == null) {
0394: if (AggregationTypeEnum.AGGREGATION
0395: .equals(lOppositeReference.getAggregationType())
0396: && pReference.isPlural()
0397: && lOppositeReference.isPlural())
0398: pViolations.add(new ConstraintViolationException(
0399: pDataManagementService, pDataManagementService
0400: .refMetaObject(),
0401: sOperationConstraintTextBase + " The '"
0402: + lOperationName
0403: + "' Operation not found."));
0404: return;
0405: }
0406: pUnclaimedOperations.remove(lOperation); // Claim the operation
0407: if (AggregationTypeEnum.AGGREGATION.equals(lOppositeReference
0408: .getAggregationType()) == false
0409: || pReference.isPlural() == false
0410: || lOppositeReference.isPlural() == false) {
0411: pViolations.add(new ConstraintViolationException(
0412: pDataManagementService, pDataManagementService
0413: .refMetaObject(),
0414: sOperationConstraintTextBase + " The '"
0415: + lOperationName
0416: + "' Operation unexpected."));
0417: return;
0418: }
0419: // Validate operation details
0420: // Input Fields - only verify that the ones that we need exist. The extra ones are allowed
0421: {
0422: // Entity key parameter
0423: {
0424: String lOperationInputFieldName = suggestEntityKeyInputParameterName(lReferencingEntityName);
0425: OperationInputField lInputField = lOperation
0426: .findInputField(lOperationInputFieldName);
0427: if (lInputField != null) {
0428: Structure lEntityKeyStructure = pDataManagementService
0429: .getServicemodule() != null ? pDataManagementService
0430: .getServicemodule()
0431: .findStructure(
0432: StylesheetImpl
0433: .getEntityKeyStructureName(lReferencingEntityName))
0434: : null;
0435: if (lEntityKeyStructure != null
0436: && lEntityKeyStructure.equals(lInputField
0437: .getStructureType()) == false)
0438: pViolations
0439: .add(new ConstraintViolationException(
0440: lInputField,
0441: lInputField.refMetaObject(),
0442: sReferencingEntityKeyInputFieldConstraintTextBase
0443: + " The '"
0444: + lOperationInputFieldName
0445: + "' input field has wrong type."));
0446: if (lInputField.isArray())
0447: pViolations
0448: .add(new ConstraintViolationException(
0449: lInputField,
0450: lInputField.refMetaObject(),
0451: sReferencingEntityKeyInputFieldConstraintTextBase
0452: + " The '"
0453: + lOperationInputFieldName
0454: + "' input field is an array, which is wrong."));
0455: } else
0456: pViolations.add(new ConstraintViolationException(
0457: lOperation, lOperation.refMetaObject(),
0458: sReferencingEntityKeyInputFieldConstraintTextBase
0459: + " The '"
0460: + lOperationInputFieldName
0461: + "' input field is missing."));
0462: }
0463: // Reference key parameter
0464: String lReferenceName = pReference.getName();
0465: if (lReferenceName != null) {
0466: String lOperationInputFieldName = suggestReferenceKeysInputParameterName(lReferenceName);
0467: OperationInputField lInputField = lOperation
0468: .findInputField(lOperationInputFieldName);
0469: if (lInputField != null) {
0470: Structure lEntityKeyStructure = pDataManagementService
0471: .getServicemodule() != null ? pDataManagementService
0472: .getServicemodule()
0473: .findStructure(
0474: StylesheetImpl
0475: .getEntityKeyStructureName(lReferencedEntityName))
0476: : null;
0477: if (lEntityKeyStructure != null
0478: && lEntityKeyStructure.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 reference 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:
0693: // Work on the servicemodule
0694: String lOperationName = suggestOperationName(
0695: pReferencingEntityName, pReferencePluralName);
0696: Operation lOperation = pDataManagementService
0697: .findOperation(lOperationName);
0698: if (lOperation == null) {
0699: lOperation = mModelAssistantImpl.mOperationClass
0700: .createOperation();
0701: lOperation.setService(pDataManagementService);
0702: lOperation.setName(lOperationName);
0703: }
0704: lOperation.setDescription(suggestOperationDescription(
0705: pReferencingEntityName, pReferencePluralName));
0706: lOperation.setTransactionPolicy(TransactionPolicyEnum.REQUIRED);
0707: lOperation.setQuery(false);
0708: // Input Fields
0709: {
0710: Collection lOperationInputFields = lOperation
0711: .getInputFields();
0712: List lUnprocessedInputFields = new ArrayList();
0713: lUnprocessedInputFields.addAll(lOperationInputFields);
0714: // Add entity key parameter
0715: {
0716: String lOperationInputFieldName = suggestEntityKeyInputParameterName(pReferencingEntityName);
0717: OperationInputField lInputField = lOperation
0718: .findInputField(lOperationInputFieldName);
0719: if (lInputField == null) {
0720: lInputField = mModelAssistantImpl.mOperationInputFieldClass
0721: .createOperationInputField();
0722: lInputField.setName(lOperationInputFieldName);
0723: lInputField.setOperation(lOperation);
0724: } else {
0725: lUnprocessedInputFields.remove(lInputField);
0726: }
0727: lInputField
0728: .setDescription(suggestEntityKeyInputParameterDescription(pReferencingEntityName));
0729: lInputField.setArray(false);
0730: lInputField.setDataType(null);
0731: Structure lEntityKeyStructure = pDataManagementService
0732: .getServicemodule() != null ? pDataManagementService
0733: .getServicemodule()
0734: .findStructure(
0735: StylesheetImpl
0736: .getEntityKeyStructureName(pReferencingEntityName))
0737: : null;
0738: lInputField.setStructureType(lEntityKeyStructure);
0739: }
0740: // Add reference key parameter
0741: String lReferenceName = pReference.getName();
0742: if (lReferenceName != null) {
0743: String lOperationInputFieldName = suggestReferenceKeysInputParameterName(lReferenceName);
0744: OperationInputField lInputField = lOperation
0745: .findInputField(lOperationInputFieldName);
0746: if (lInputField == null) {
0747: lInputField = mModelAssistantImpl.mOperationInputFieldClass
0748: .createOperationInputField();
0749: lInputField.setName(lOperationInputFieldName);
0750: lInputField.setOperation(lOperation);
0751: } else {
0752: lUnprocessedInputFields.remove(lInputField);
0753: }
0754: lInputField
0755: .setDescription(suggestReferenceKeysInputParameterDescription(pReferencePluralName));
0756: lInputField.setArray(true);
0757: lInputField.setDataType(null);
0758:
0759: Structure lEntityKeyStructure = null;
0760: Servicemodule lServicemodule = pDataManagementService
0761: .getServicemodule();
0762: if (lServicemodule != null
0763: && lReferencedEntityName != null)
0764: lEntityKeyStructure = lServicemodule
0765: .findStructure(StylesheetImpl
0766: .getEntityKeyStructureName(lReferencedEntityName));
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 "add"
0977: + StringUtils.suggestName(pReferencePluralName, true,
0978: false) + "To"
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 "Adds one or more " + pReferencePluralName
0987: + " to 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 added.";
1018: }
1019: }
|