001: /*
002: * Copyright 2004-2006 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.compass.core.config.process;
018:
019: import java.util.HashMap;
020: import java.util.Iterator;
021: import java.util.List;
022:
023: import org.compass.core.Property;
024: import org.compass.core.config.CompassEnvironment;
025: import org.compass.core.config.CompassSettings;
026: import org.compass.core.converter.ConverterLookup;
027: import org.compass.core.engine.naming.PropertyNamingStrategy;
028: import org.compass.core.mapping.CompassMapping;
029: import org.compass.core.mapping.Mapping;
030: import org.compass.core.mapping.MappingException;
031: import org.compass.core.mapping.ResourcePropertyMapping;
032: import org.compass.core.mapping.osem.ClassIdPropertyMapping;
033: import org.compass.core.mapping.osem.ClassMapping;
034: import org.compass.core.mapping.osem.ClassPropertyMapping;
035: import org.compass.core.mapping.osem.ClassPropertyMetaDataMapping;
036: import org.compass.core.mapping.osem.OsemMappingIterator;
037:
038: /**
039: * @author kimchy
040: */
041: public class InternalIdsMappingProcessor implements MappingProcessor {
042:
043: private CompassSettings settings;
044:
045: private ConverterLookup converterLookup;
046:
047: public CompassMapping process(CompassMapping compassMapping,
048: PropertyNamingStrategy namingStrategy,
049: ConverterLookup converterLookup, CompassSettings settings)
050: throws MappingException {
051:
052: this .settings = settings;
053: this .converterLookup = converterLookup;
054:
055: for (Iterator it = compassMapping.mappingsIt(); it.hasNext();) {
056: Mapping m = (Mapping) it.next();
057: if (m instanceof ClassMapping) {
058: ClassMapping classMapping = (ClassMapping) m;
059: if (classMapping.isSupportUnmarshall()) {
060: buildClassMetaDataIds(classMapping);
061: } else {
062: buildInternalIdForIdProperties(classMapping);
063: }
064: }
065: }
066: return compassMapping;
067: }
068:
069: /**
070: * Build internal ids only for the class property id mappings when we
071: * do not support un-marshalling.
072: */
073: private void buildInternalIdForIdProperties(
074: ClassMapping classMapping) {
075: List idMappings = classMapping.findClassPropertyIdMappings();
076: for (Iterator it = idMappings.iterator(); it.hasNext();) {
077: MappingProcessorUtils.addInternalId(settings,
078: converterLookup, (ClassPropertyMapping) it.next(),
079: true);
080: }
081: }
082:
083: /**
084: * <p>Go over all the attributes in the class (note that it takes all the
085: * component attributes and so on) and does the following:
086: * <li>If the attributed is marked with <code>managedId="true"</code>,
087: * or it has no meta data associated with it, compass will create a new
088: * internal id</li>
089: * <li>If the class property is marked with <code>managedId="auto"</code>
090: * and there is a meta data in the attribute that is unique, use it as the
091: * attribute id, otherwise create a new internal id</li>
092: * <li>If the attributed is marked with <code>managedId="false"</code>,
093: * the id will be the first meta data</li>
094: *
095: * <p>When ref alias has more than one alias, duplicate mappings might exists.
096: * Duplicate mappings are mappings that are shared by several mappings.
097: * {@link org.compass.core.mapping.osem.OsemMappingIterator.ClassPropertyAndResourcePropertyGatherer}
098: * ignores this duplicates, and only process the first one. Later, in the post process
099: * stage ({@link org.compass.core.config.process.PostProcessorMappingProcessor}, the ones
100: * that got skipped will be replced with the ones that were (they are the same).
101: *
102: * @param classMapping
103: */
104: private void buildClassMetaDataIds(ClassMapping classMapping) {
105: OsemMappingIterator.ClassPropertyAndResourcePropertyGatherer callback = new OsemMappingIterator.ClassPropertyAndResourcePropertyGatherer();
106: OsemMappingIterator.iterateMappings(callback, classMapping);
107:
108: HashMap propertyMappingsMap = new HashMap();
109: List pMappings = callback.getResourcePropertyMappings();
110: for (Iterator it = pMappings.iterator(); it.hasNext();) {
111: ResourcePropertyMapping pMapping = (ResourcePropertyMapping) it
112: .next();
113: // no need to count the ones we don't store since they won't
114: // be reflected when we unmarshall the data
115: if (pMapping.getStore() == Property.Store.NO) {
116: continue;
117: }
118: Integer count = (Integer) propertyMappingsMap.get(pMapping
119: .getName());
120: if (count == null) {
121: count = new Integer(1);
122: } else {
123: count = new Integer(count.intValue() + 1);
124: }
125: propertyMappingsMap.put(pMapping.getName(), count);
126: }
127:
128: List classPropertyMappings = callback
129: .getClassPropertyMappings();
130: for (Iterator it = classPropertyMappings.iterator(); it
131: .hasNext();) {
132: ClassPropertyMapping classPropertyMapping = (ClassPropertyMapping) it
133: .next();
134:
135: // first, set the managed id if not set usign default (up to class mapping, and if
136: // not set, up to Compass settings, and if not there, default to auto).
137: if (classPropertyMapping.getManagedId() == null) {
138: if (classMapping.getManagedId() == null) {
139: String globalManagedId = settings.getSetting(
140: CompassEnvironment.Osem.MANAGED_ID_DEFAULT,
141: "auto");
142: classPropertyMapping
143: .setManagedId(ClassPropertyMapping.ManagedId
144: .fromString(globalManagedId));
145: } else {
146: classPropertyMapping.setManagedId(classMapping
147: .getManagedId());
148: }
149: }
150:
151: boolean mustBeUnTokenized = false;
152: if (classPropertyMapping instanceof ClassIdPropertyMapping) {
153: mustBeUnTokenized = true;
154: }
155: if (classPropertyMapping.isIdPropertySet()) {
156: // the id has been set already (for example - in case of reference)
157: continue;
158: } else if (classPropertyMapping.getManagedId() == ClassPropertyMapping.ManagedId.TRUE
159: || classPropertyMapping.mappingsSize() == 0) {
160: MappingProcessorUtils.addInternalId(settings,
161: converterLookup, classPropertyMapping,
162: mustBeUnTokenized);
163: } else if (classPropertyMapping.getManagedId() == ClassPropertyMapping.ManagedId.AUTO) {
164: autoAddIfRequiredInternalId(propertyMappingsMap,
165: classPropertyMapping, mustBeUnTokenized);
166: } else if (classPropertyMapping.getManagedId() == ClassPropertyMapping.ManagedId.NO_STORE) {
167: boolean allMetaDataHasStoreNo = true;
168: for (int i = 0; i < classPropertyMapping.mappingsSize(); i++) {
169: ClassPropertyMetaDataMapping pMapping = (ClassPropertyMetaDataMapping) classPropertyMapping
170: .getMapping(i);
171: if (!pMapping.canActAsPropertyId()) {
172: continue;
173: }
174: if (pMapping.getStore() != Property.Store.NO) {
175: allMetaDataHasStoreNo = false;
176: }
177: }
178: if (!allMetaDataHasStoreNo) {
179: autoAddIfRequiredInternalId(propertyMappingsMap,
180: classPropertyMapping, mustBeUnTokenized);
181: } // else, don't set the id property, and don't unmarshall it
182:
183: } else if (classPropertyMapping.getManagedId() == ClassPropertyMapping.ManagedId.NO) {
184: // do nothing, don't set the managed id, won't be unmarshallled
185: } else { // ManagedId.FALSE
186: // mark the first one as the id, the user decides
187: classPropertyMapping.setIdPropertyIndex(0);
188: }
189: }
190: }
191:
192: private void autoAddIfRequiredInternalId(
193: HashMap propertyMappingsMap,
194: ClassPropertyMapping classPropertyMapping,
195: boolean mustBeUnTokenized) {
196: boolean foundPropertyId = false;
197: for (int i = 0; i < classPropertyMapping.mappingsSize(); i++) {
198: ClassPropertyMetaDataMapping pMapping = (ClassPropertyMetaDataMapping) classPropertyMapping
199: .getMapping(i);
200: if (!pMapping.canActAsPropertyId()) {
201: continue;
202: }
203: if (!propertyMappingsMap.containsKey(pMapping.getName())) {
204: // there is none defined, this means that they got filtered out since they are not
205: // stored. continue in case we manage to find a candidate for internal id, if not
206: // we need to add an internal one in such cases
207: continue;
208: }
209: // if there is only one mapping, and it is stored, use it as the id
210: if (((Integer) propertyMappingsMap.get(pMapping.getName()))
211: .intValue() == 1
212: && (pMapping.getStore() == Property.Store.YES || pMapping
213: .getStore() == Property.Store.COMPRESS)) {
214: if (mustBeUnTokenized
215: && pMapping.getIndex() != Property.Index.UN_TOKENIZED) {
216: continue;
217: }
218: classPropertyMapping.setIdPropertyIndex(i);
219: foundPropertyId = true;
220: break;
221: }
222: }
223:
224: if (!foundPropertyId) {
225: MappingProcessorUtils.addInternalId(settings,
226: converterLookup, classPropertyMapping,
227: mustBeUnTokenized);
228: }
229: }
230:
231: }
|