/*
* Copyright 2004-2009 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.compass.core.test.map;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import org.compass.core.CompassException;
import org.compass.core.Property;
import org.compass.core.Resource;
import org.compass.core.ResourceFactory;
import org.compass.core.config.CompassConfigurable;
import org.compass.core.config.CompassSettings;
import org.compass.core.converter.ConversionException;
import org.compass.core.converter.Converter;
import org.compass.core.converter.mapping.SuggestManagedIdConverter;
import org.compass.core.engine.naming.PropertyNamingStrategy;
import org.compass.core.mapping.Mapping;
import org.compass.core.mapping.ResourcePropertyMapping;
import org.compass.core.mapping.osem.ManagedId;
import org.compass.core.marshall.MarshallingContext;
import org.compass.core.util.StringUtils;
/**
* This is a sample converter that can handle {@link Map} and save dynamic properties into the index.
* <p/>
* Saves dynamic properties, with the map keys as the properties names and map values as the property
* values. Uses the Object toString to convert the key and values objects to strings.
* <p/>
* If the converter will support unmarshalling, than assumes that the key and the value are of type
* {@link String}. Saves the keys as comma delimited string under an internal property, and the
* values the same under a different property.
* <p/>
* Note, that using this converter might affect the Class mapping that uses the Map as a property.
* If another meta-data is mapped to a name that might be one of the dynamic property names, it must
* be set to have the intenal id always generated. It also applies to a class that has this class as
* component mapping.
* <p/>
* This Converter is provided as a baseline for different maps converters that might hold different
* object types than Strings.
*
* @author kimchy
*/
public class MapConverter implements Converter, CompassConfigurable, SuggestManagedIdConverter {
private boolean supportUnmarshall = true;
public void configure(CompassSettings settings) throws CompassException {
supportUnmarshall = settings.getSettingAsBoolean("supportUnmarshall", true);
}
public ManagedId suggestManagedId() {
return ManagedId.FALSE;
}
public boolean marshall(Resource resource, Object root, Mapping mapping, MarshallingContext context) throws ConversionException {
if (root == null && !context.handleNulls()) {
return false;
}
ResourcePropertyMapping resourcePropertyMapping = (ResourcePropertyMapping) mapping;
ResourceFactory resourceFactory = context.getResourceFactory();
Map map = (Map) root;
for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
Map.Entry entry = (Map.Entry) it.next();
Property p = resourceFactory.createProperty(entry.getKey().toString(), entry.getValue().toString(),
resourcePropertyMapping.getStore(), resourcePropertyMapping.getIndex(), resourcePropertyMapping.getTermVector());
p.setBoost(resourcePropertyMapping.getBoost());
resource.addProperty(p);
}
if (supportUnmarshall) {
StringBuffer keys = new StringBuffer();
StringBuffer values = new StringBuffer();
for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
Map.Entry entry = (Map.Entry) it.next();
keys.append(entry.getKey().toString()).append(",");
values.append(entry.getValue().toString()).append(",");
}
PropertyNamingStrategy propertyNamingStrategy =
context.getSession().getCompass().getSearchEngineFactory().getPropertyNamingStrategy();
// save keys (under an internal name)
String keyPath = propertyNamingStrategy.buildPath(resourcePropertyMapping.getPath(), "keys").getPath();
Property p = resourceFactory.createProperty(keyPath, keys.toString(),
Property.Store.YES, Property.Index.NOT_ANALYZED);
resource.addProperty(p);
// save values (under an internal name)
String valuePath = propertyNamingStrategy.buildPath(resourcePropertyMapping.getPath(), "values").getPath();
p = resourceFactory.createProperty(valuePath, values.toString(), Property.Store.YES, Property.Index.NOT_ANALYZED);
resource.addProperty(p);
}
return true;
}
public Object unmarshall(Resource resource, Mapping mapping, MarshallingContext context) throws ConversionException {
if (!supportUnmarshall) {
return null;
}
ResourcePropertyMapping resourcePropertyMapping = (ResourcePropertyMapping) mapping;
PropertyNamingStrategy propertyNamingStrategy =
context.getSession().getCompass().getSearchEngineFactory().getPropertyNamingStrategy();
// save keys (under an internal name)
String keyPath = propertyNamingStrategy.buildPath(resourcePropertyMapping.getPath(), "keys").getPath();
String strKeys = resource.getValue(keyPath);
if (strKeys == null) {
return null;
}
String valuePath = propertyNamingStrategy.buildPath(resourcePropertyMapping.getPath(), "values").getPath();
String strValues = resource.getValue(valuePath);
String[] keys = StringUtils.tokenizeToStringArray(strKeys, ",");
String[] values = StringUtils.tokenizeToStringArray(strValues, ",");
if (keys.length != values.length) {
throw new ConversionException("Keys with length [" + keys.length + "] does not match values length ["
+ values.length + "]");
}
Map map = new HashMap();
for (int i = 0; i < keys.length; i++) {
map.put(keys[i], values[i]);
}
return map;
}
public boolean isSupportUnmarshall() {
return supportUnmarshall;
}
public void setSupportUnmarshall(boolean supportUnmarshall) {
this.supportUnmarshall = supportUnmarshall;
}
}