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.modelassistant.metabossmodel.implicittypes;
016:
017: import java.util.Collection;
018: import java.util.Comparator;
019: import java.util.Iterator;
020: import java.util.List;
021: import java.util.Set;
022: import java.util.TreeSet;
023:
024: import javax.jmi.reflect.ConstraintViolationException;
025:
026: import com.metaboss.sdlctools.models.metabossmodel.datadictionarymodel.DataType;
027: import com.metaboss.sdlctools.models.metabossmodel.datadictionarymodel.Namespace;
028: import com.metaboss.sdlctools.models.metabossmodel.datadictionarymodel.Property;
029: import com.metaboss.sdlctools.models.metabossmodel.datadictionarymodel.TypeTemplate;
030: import com.metaboss.sdlctools.models.metabossmodel.enterprisemodel.systemimplementationmodel.Entity;
031: import com.metaboss.sdlctools.models.metabossmodel.enterprisemodel.systemimplementationmodel.EntityStereotypeEnum;
032:
033: /** This class holds details about Entity VersionId DataType
034: * being processed. Used internally in the Assistant impl */
035: class EntityVersionIdDataTypeHelper {
036: // Utility comparator, which is used to sort properties in order of deletion
037: // The problem is that when parent property is deleted - the child property is deleted too, so
038: // when we iterate through unused properties and issue refDelete() - we may hit already deleted property.
039: // This comparator sorts the properties in the reverse string sort order of the keys,
040: // which ensures that properties are sorted in the right order for deletion (child properties before parent ones)
041: private static Comparator sPropertiesToDeleteComparator = new Comparator() {
042: public int compare(Object o1, Object o2) {
043: return ((Property) o2).getKey().compareTo(
044: ((Property) o1).getKey());
045: }
046: };
047:
048: private ModelAssistantImpl mModelAssistantImpl;
049: private Set mUnusedProperties = new TreeSet(
050: sPropertiesToDeleteComparator);
051: private DataType mEntityVersionIdDataType = null;
052: private TypeTemplate mEntityVersionIdFieldTypeTemplate = null;
053:
054: // This helper is looking at the conditions and ensuring the inegrity of the data type
055: // it will create the missing data type and delete exta one if necessary
056: static void verifyEntityVersionIdDataTypeIntegrity(
057: Collection pViolations,
058: ModelAssistantImpl pModelAssistantImpl, Entity pEntity,
059: List pUnprocessedDataTypes, HelperContext pHelperContext) {
060: Namespace lDomainNamespace = pHelperContext
061: .getDomainNamespace();
062: if (lDomainNamespace == null)
063: return;
064: TypeTemplate lDesiredTypeTemplate = pHelperContext
065: .getEntityVersionIdFieldTypeTemplate();
066: if (lDesiredTypeTemplate == null)
067: return;
068:
069: // Each modifiable entity must have version id data type
070: if (pEntity.getStereotype().equals(
071: EntityStereotypeEnum.CARD_FILE)) {
072: String lExpectedDataTypeName = StylesheetImpl
073: .getEntityVersionIdDataTypeName(pEntity.getName());
074: DataType lVersionIdDataTypeInNamespace = lDomainNamespace
075: .findDataType(lExpectedDataTypeName);
076: if (lVersionIdDataTypeInNamespace != null) {
077: // Remove this data type from the list of unprocessed ones
078: if (pUnprocessedDataTypes != null)
079: pUnprocessedDataTypes
080: .remove(lVersionIdDataTypeInNamespace);
081: // Verify that the entity is actually pointing to this data type
082: DataType lVersionIdDataTypeInEntity = pEntity
083: .getVersionIdDataType();
084: if (lVersionIdDataTypeInEntity != null
085: && lVersionIdDataTypeInEntity
086: .equals(lVersionIdDataTypeInNamespace) == false)
087: pViolations
088: .add(new ConstraintViolationException(
089: pEntity,
090: pEntity.refMetaObject(),
091: "Modifiable Entity must always be associated with the Entity Version Id data type residing in System namespace."));
092:
093: // Verify that this data type is based on prescribed template
094: TypeTemplate lActualTypeTemplate = lVersionIdDataTypeInNamespace
095: .getTypetemplate();
096: if (lActualTypeTemplate == null
097: || lActualTypeTemplate
098: .equals(lDesiredTypeTemplate) == false)
099: pViolations
100: .add(new ConstraintViolationException(
101: lVersionIdDataTypeInNamespace,
102: lVersionIdDataTypeInNamespace
103: .refMetaObject(),
104: "The Entity Version Id data type must be based on a '"
105: + lDesiredTypeTemplate
106: .getName()
107: + "' typetemplate. The '"
108: + lExpectedDataTypeName
109: + "' data type is not based on this template."));
110: } else
111: pViolations
112: .add(new ConstraintViolationException(
113: lDomainNamespace,
114: lDomainNamespace.refMetaObject(),
115: "System namespace for Domain must contain an Entity Version Id data type for every modifiable entity in the domain. Entity '"
116: + pEntity.getName()
117: + "' does not have corresponding '"
118: + lExpectedDataTypeName
119: + "' data type."));
120: }
121: }
122:
123: // This helper is looking at the conditions and ensuring the inegrity of the data type
124: // it will create the missing data type and delete exta one if necessary
125: static void ensureEntityVersionIdDataTypeIntegrity(
126: ModelAssistantImpl pModelAssistantImpl, Entity pEntity,
127: List pUnprocessedDataTypes, HelperContext pHelperContext) {
128: if (pEntity.getStereotype().equals(
129: EntityStereotypeEnum.CARD_FILE)) {
130: // Ensure that data type exists
131: ensureEntityVersionIdDataTypeExists(pModelAssistantImpl,
132: pEntity, pUnprocessedDataTypes, pHelperContext);
133: // Now work on all properties
134: EntityVersionIdDataTypeHelper lDataTypeHelper = new EntityVersionIdDataTypeHelper(
135: pModelAssistantImpl, pEntity.getVersionIdDataType());
136: // Work on properties
137: lDataTypeHelper.markPropertiesAsUnused();
138: // Delete all still unused properties
139: lDataTypeHelper.deleteUnusedProperties();
140: } else
141: ensureEntityVersionIdDataTypeAbsent(pEntity,
142: pUnprocessedDataTypes, pHelperContext);
143: }
144:
145: // This helper is looking after creation of absent entity state data type
146: // It returns the newly created or found Data Type or null if it can not be created
147: // The namespaces are optional parameters - if they are null - they will be discovered inside this method
148: // and if they are unobtainable - this method will fail to work and return null. This is provided to save some time
149: // during batch operations
150: static DataType ensureEntityVersionIdDataTypeExists(
151: ModelAssistantImpl pModelAssistantImpl, Entity pEntity,
152: List pUnprocessedDataTypes, HelperContext pHelperContext) {
153: Namespace lDomainNamespace = pHelperContext
154: .getDomainNamespace();
155: if (lDomainNamespace == null)
156: return null;
157: String lEntityVersionIdDataTypeName = StylesheetImpl
158: .getEntityVersionIdDataTypeName(pEntity.getName());
159: DataType lEntityVersionIdDataType = lDomainNamespace
160: .findDataType(lEntityVersionIdDataTypeName);
161: TypeTemplate lEntityVersionIdDataTypeTypeTemplate = pHelperContext
162: .getEntityVersionIdFieldTypeTemplate();
163: if (lEntityVersionIdDataTypeTypeTemplate == null)
164: return null;
165: if (lEntityVersionIdDataType == null) {
166: lEntityVersionIdDataType = pModelAssistantImpl.mDataTypeClass
167: .createDataType();
168: lEntityVersionIdDataType
169: .setName(lEntityVersionIdDataTypeName);
170: lDomainNamespace.getDataTypes().add(
171: lEntityVersionIdDataType);
172: } else {
173: if (pUnprocessedDataTypes != null)
174: pUnprocessedDataTypes.remove(lEntityVersionIdDataType);
175: }
176: // Because the data type is located by name - it is possible that in fact it does not have
177: // features set up as we would like them to be. We need just to override them
178: lEntityVersionIdDataType.setDescription(StylesheetImpl
179: .getEntityVersionIdDataTypeDescription(pEntity
180: .getName()));
181: lEntityVersionIdDataType
182: .setTypetemplate(lEntityVersionIdDataTypeTypeTemplate);
183: pEntity.setVersionIdDataType(lEntityVersionIdDataType);
184: // Here we would need to work on mandatory properties, but this type has none
185: return lEntityVersionIdDataType;
186: }
187:
188: // This helper is looking after creation of absent data type
189: // The namespace is optional parameters - if it is null it will be discovered inside this method
190: // and if it is unobtainable - this method will fail to work and return false. This is provided to save some time
191: // during batch operations
192: static boolean ensureEntityVersionIdDataTypeAbsent(Entity pEntity,
193: List pUnprocessedDataTypes, HelperContext pHelperContext) {
194: Namespace lDomainNamespace = pHelperContext
195: .getDomainNamespace();
196: if (lDomainNamespace == null)
197: return false;
198: String lEntityVersionIdDataTypeName = StylesheetImpl
199: .getEntityVersionIdDataTypeName(pEntity.getName());
200: DataType lEntityVersionIdDataType = lDomainNamespace
201: .findDataType(lEntityVersionIdDataTypeName);
202: if (lEntityVersionIdDataType != null) {
203: if (pUnprocessedDataTypes != null)
204: pUnprocessedDataTypes.remove(lEntityVersionIdDataType);
205: lEntityVersionIdDataType.refDelete();
206: }
207: // Just in case - set the datatype to null
208: pEntity.setVersionIdDataType(null);
209: return true; // Done
210: }
211:
212: public EntityVersionIdDataTypeHelper(
213: ModelAssistantImpl pModelAssistantImpl,
214: DataType pEntityVersionIdDataType) {
215: mModelAssistantImpl = pModelAssistantImpl;
216: mEntityVersionIdDataType = pEntityVersionIdDataType;
217: mEntityVersionIdFieldTypeTemplate = mEntityVersionIdDataType
218: .getTypetemplate();
219: }
220:
221: // Marks all optional properties as unused.
222: // Every subsequent property action will remove from this list a property, which is not unused one
223: void markPropertiesAsUnused() {
224: // Put all properties to unused apart from mandatory ones
225: for (Iterator lPropertiesIterator = mEntityVersionIdDataType
226: .getCombinedTypetemplateProperties().iterator(); lPropertiesIterator
227: .hasNext();) {
228: Property lProperty = (Property) lPropertiesIterator.next();
229: // Here we could filter out mandatory properties, so they never ever get into the unused
230: // set. This would ensure that they never deleted. This data type has not got
231: // any mandatory properties - so all properties will go into the unused set
232: mUnusedProperties.add(lProperty);
233: }
234: }
235:
236: // Deletes all properties in unused set at the moment. Normally
237: // we start with marking all properties as unused, than going though all property manipulations
238: // and than calling this method to delete all whjat is left
239: void deleteUnusedProperties() {
240: for (Iterator lUnprocessedPropertiesIterator = mUnusedProperties
241: .iterator(); lUnprocessedPropertiesIterator.hasNext();) {
242: Property lProperty = (Property) lUnprocessedPropertiesIterator
243: .next();
244: lProperty.refDelete();
245: }
246: }
247: }
|