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.converter.mapping.osem;
018:
019: import org.compass.core.Property;
020: import org.compass.core.Resource;
021: import org.compass.core.ResourceFactory;
022: import org.compass.core.accessor.Getter;
023: import org.compass.core.converter.ConversionException;
024: import org.compass.core.converter.Converter;
025: import org.compass.core.converter.mapping.CollectionResourceWrapper;
026: import org.compass.core.mapping.Mapping;
027: import org.compass.core.mapping.osem.AbstractCollectionMapping;
028: import org.compass.core.mapping.osem.ClassMapping;
029: import org.compass.core.marshall.MarshallingContext;
030: import org.compass.core.marshall.MarshallingEnvironment;
031:
032: /**
033: * @author kimchy
034: */
035: public abstract class AbstractCollectionMappingConverter implements
036: Converter {
037:
038: public static final String COLLECTION_RESOURCE_WRAPPER_KEY = "$crwk";
039:
040: public boolean marshall(Resource resource, Object root,
041: Mapping mapping, MarshallingContext context)
042: throws ConversionException {
043: ResourceFactory resourceFactory = context.getResourceFactory();
044: AbstractCollectionMapping colMapping = (AbstractCollectionMapping) mapping;
045: ClassMapping rootClassMapping = (ClassMapping) context
046: .getAttribute(ClassMappingConverter.ROOT_CLASS_MAPPING_KEY);
047:
048: // if we have a null value, we check if we need to handle null values
049: // if so, we will note the fact that it is null under the size attribute
050: if (root == null) {
051: if (context.handleNulls()
052: && rootClassMapping.isSupportUnmarshall()) {
053: Property p = resourceFactory.createProperty(colMapping
054: .getColSizePath().getPath(), resourceFactory
055: .getNullValue(), Property.Store.YES,
056: Property.Index.UN_TOKENIZED);
057: p.setOmitNorms(true);
058: resource.addProperty(p);
059: return true;
060: } else {
061: return false;
062: }
063: }
064:
065: if (rootClassMapping.isSupportUnmarshall()) {
066: if (colMapping.getCollectionType() == AbstractCollectionMapping.CollectionType.UNKNOWN) {
067: Property p = resourceFactory
068: .createProperty(
069: colMapping.getCollectionTypePath()
070: .getPath(),
071: AbstractCollectionMapping.CollectionType
072: .toString(getRuntimeCollectionType(root)),
073: Property.Store.YES,
074: Property.Index.UN_TOKENIZED);
075: p.setOmitNorms(true);
076: resource.addProperty(p);
077: }
078: // for null values in entities within the collection, they must be saved
079: // so the order will be maintained
080: context.setHandleNulls(colMapping.getPath());
081: }
082:
083: int size = marshallIterateData(root, colMapping, resource,
084: context);
085:
086: if (rootClassMapping.isSupportUnmarshall()) {
087: context.removeHandleNulls(colMapping.getPath());
088: Property p = resourceFactory.createProperty(colMapping
089: .getColSizePath().getPath(),
090: Integer.toString(size), Property.Store.YES,
091: Property.Index.UN_TOKENIZED);
092: p.setOmitNorms(true);
093: resource.addProperty(p);
094: }
095:
096: return true;
097: }
098:
099: protected abstract AbstractCollectionMapping.CollectionType getRuntimeCollectionType(
100: Object root);
101:
102: /**
103: * Marhall the data, returning the number of elements that were actually stored in the index
104: * (and can later be read).
105: */
106: protected abstract int marshallIterateData(Object root,
107: AbstractCollectionMapping colMapping, Resource resource,
108: MarshallingContext context);
109:
110: public Object unmarshall(Resource resource, Mapping mapping,
111: MarshallingContext context) throws ConversionException {
112: AbstractCollectionMapping colMapping = (AbstractCollectionMapping) mapping;
113: ResourceFactory resourceFactory = context.getResourceFactory();
114:
115: Property pColSize = resource.getProperty(colMapping
116: .getColSizePath().getPath());
117: if (pColSize == null) {
118: // when we marshalled it, it was null
119: return null;
120: }
121: String sColSize = pColSize.getStringValue();
122: // if we marshalled it and marked it as null, return the null value
123: if (resourceFactory.isNullValue(sColSize)) {
124: return null;
125: }
126:
127: AbstractCollectionMapping.CollectionType collectionType = colMapping
128: .getCollectionType();
129: if (colMapping.getCollectionType() == AbstractCollectionMapping.CollectionType.UNKNOWN) {
130: // try and read the collection from the index
131: Property pColllectionType = resource.getProperty(colMapping
132: .getCollectionTypePath().getPath());
133: if (pColllectionType == null) {
134: throw new ConversionException(
135: "Expected to find the collection/arraytype stored in the resource");
136: }
137: collectionType = AbstractCollectionMapping.CollectionType
138: .fromString(pColllectionType.getStringValue());
139: }
140:
141: int size = Integer.parseInt(sColSize);
142:
143: Object col = createColObject(colMapping.getGetter(),
144: collectionType, size);
145:
146: // for null values in enteties within the collection, they must be saved
147: // so the order will be maintained
148: context.setHandleNulls(colMapping.getPath());
149:
150: // if we already wrapped the resource with a collection wrapper, use it
151: // if not, create a new one. Also, mark if we created it so we can clean up afterwards
152: boolean createdCollectionResourceWrapper = false;
153: CollectionResourceWrapper crw = (CollectionResourceWrapper) context
154: .getAttribute(COLLECTION_RESOURCE_WRAPPER_KEY);
155: if (crw == null) {
156: createdCollectionResourceWrapper = true;
157: crw = new CollectionResourceWrapper(resource);
158: context.setAttribute(COLLECTION_RESOURCE_WRAPPER_KEY, crw);
159: }
160:
161: Object current = context
162: .getAttribute(MarshallingEnvironment.ATTRIBUTE_CURRENT);
163: Mapping elementMapping = colMapping.getElementMapping();
164: for (int i = 0; i < size; i++) {
165: context.setAttribute(
166: MarshallingEnvironment.ATTRIBUTE_CURRENT, current);
167: Object value = elementMapping.getConverter().unmarshall(
168: crw, elementMapping, context);
169: if (value != null) {
170: addValue(col, i, value);
171: }
172: }
173:
174: if (createdCollectionResourceWrapper) {
175: context.removeAttribute(COLLECTION_RESOURCE_WRAPPER_KEY);
176: }
177:
178: context.removeHandleNulls(colMapping.getPath());
179:
180: return col;
181: }
182:
183: protected abstract Object createColObject(Getter getter,
184: AbstractCollectionMapping.CollectionType collectionType,
185: int size);
186:
187: protected abstract void addValue(Object col, int index, Object value);
188: }
|