/*
*
* Copyright 2010 Luca Molino (luca.molino--AT--assetdata.it)
*
* 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.romaframework.aspect.data;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.romaframework.aspect.data.feature.DataFieldFeatures;
import org.romaframework.core.Roma;
import org.romaframework.core.aspect.Aspect;
import org.romaframework.core.exception.ConfigurationNotFoundException;
import org.romaframework.core.flow.Controller;
import org.romaframework.core.module.SelfRegistrantConfigurableModule;
import org.romaframework.core.schema.SchemaAction;
import org.romaframework.core.schema.SchemaClass;
import org.romaframework.core.schema.SchemaClassDefinition;
import org.romaframework.core.schema.SchemaEvent;
import org.romaframework.core.schema.SchemaField;
import org.romaframework.core.schema.SchemaHelper;
import org.romaframework.core.schema.SchemaObject;
import org.romaframework.core.schema.SchemaObjectListener;
/**
* @author luca.molino
*
*/
public class DataBindingAspect extends SelfRegistrantConfigurableModule<String> implements Aspect, SchemaObjectListener {
public static final String ASPECT_NAME = "data";
private static Log logger = LogFactory.getLog(DataBindingAspect.class);
public DataBindingAspect() {
}
public String aspectName() {
return ASPECT_NAME;
}
@Override
public void startup() throws RuntimeException {
super.startup();
Controller.getInstance().registerListener(SchemaObjectListener.class, this);
}
public void beginConfigClass(SchemaClassDefinition iClass) {
}
public void configClass(SchemaClassDefinition iClass) {
}
public void configField(SchemaField iField) {
}
public void configAction(SchemaAction iAction) {
}
public void configEvent(SchemaEvent iEvent) {
}
public void endConfigClass(SchemaClassDefinition iClass) {
}
public void onCreate(SchemaObject iObject) {
if (iObject.getInstance() != null) {
for (SchemaField schemaField : iObject.getFields().values()) {
Class<?> repositoryClass = (Class<?>) schemaField.getFeature(DataFieldFeatures.REPOSITORY);
if (repositoryClass == null)
continue;
String methodName = schemaField.getFeature(DataFieldFeatures.METHOD);
String[] searchFields = schemaField.getFeature(DataFieldFeatures.SEARCH_FIELDS);
int limit = schemaField.getFeature(DataFieldFeatures.LIMIT).intValue();
Method methodToCall = getMethod(repositoryClass, methodName, searchFields);
try {
Object repository = repositoryClass.newInstance();
setResult(iObject, schemaField, repositoryClass, methodName, limit, methodToCall, repository, searchFields);
} catch (InstantiationException ie) {
throw new ConfigurationNotFoundException("Error creating instance of class " + repositoryClass.getName(), ie);
} catch (IllegalAccessException iae) {
throw new ConfigurationNotFoundException("Error creating instance of class " + repositoryClass.getName(), iae);
} catch (IllegalArgumentException iare) {
throw new ConfigurationNotFoundException("Error creating instance of class " + repositoryClass.getName(), iare);
}
}
}
}
public Object getUnderlyingComponent() {
return null;
}
protected Class<?> getRepositoryClass(String repositoryClassName) {
Class<?> repositoryClass = Roma.repository(repositoryClassName) != null ? Roma.repository(repositoryClassName).getClass() : null;
if (repositoryClass == null) {
repositoryClassName = configuration.get(repositoryClassName);
if (repositoryClassName == null || repositoryClassName.equals("")) {
throw new ConfigurationNotFoundException("Error loading repository class " + repositoryClassName + ": configuration not found.");
} else {
try {
repositoryClass = Class.forName(repositoryClassName);
} catch (ClassNotFoundException cnfe) {
logger.error("Error loading repository class " + repositoryClassName);
throw new ConfigurationNotFoundException("Error loading repository class " + repositoryClassName, cnfe);
}
}
}
return repositoryClass;
}
protected String getRepositoryClassName(SchemaField iField) {
String repositoryClassName;
if (SchemaHelper.isMultiValueObject(iField)) {
if (((Class<?>) iField.getLanguageType()).isAssignableFrom(Map.class)) {
throw new ConfigurationNotFoundException("DataField annotation is not assignable for Map (field " + iField.getName() + ")");
}
Class<?> embeddedClass = null;
if (iField.getEmbeddedType() != null) {
embeddedClass = (Class<?>) iField.getEmbeddedType().getLanguageType();
} else {
for (SchemaClass schema : iField.getEmbeddedTypeGenerics()) {
if (schema != null)
embeddedClass = (Class<?>) schema.getLanguageType();
}
}
repositoryClassName = embeddedClass.getSimpleName() + "Repository";
} else {
repositoryClassName = ((Class<?>) iField.getLanguageType()).getSimpleName() + "Repository";
}
return repositoryClassName;
}
protected List<?> setResult(SchemaObject iObject, SchemaField schemaField, Class<?> repositoryClass, String methodName, int limit, Method methodToCall, Object repository,
String[] searchFields) {
Object[] args = new Object[searchFields.length];
for (int i = 0; i < searchFields.length; i++) {
String searchFieldName = searchFields[i];
if (iObject.getField(searchFieldName) == null)
throw new ConfigurationNotFoundException("Field '" + searchFieldName + "' in class " + iObject.getSchemaClass().getName() + " not found");
args[i] = iObject.getField(searchFieldName).getValue(iObject.getInstance());
}
List<?> result = null;
try {
result = (List<?>) methodToCall.invoke(repository, args);
} catch (InvocationTargetException ite) {
throw new ConfigurationNotFoundException("Error invoking method " + methodName + " of instance " + repositoryClass.getName(), ite);
} catch (IllegalAccessException iae) {
throw new ConfigurationNotFoundException("Error invoking method " + methodName + " of instance " + repositoryClass.getName(), iae);
}
if (limit > 0 && result.size() > limit) {
schemaField.setValue(iObject.getInstance(), result.subList(0, limit));
} else {
schemaField.setValue(iObject.getInstance(), result);
}
return result;
}
protected Method getMethod(Class<?> repositoryClass, String methodName, String[] searchFields) {
Method methodToCall = null;
for (Method method : repositoryClass.getMethods()) {
if (method.getName().equals(methodName) && method.getParameterTypes().length == searchFields.length) {
methodToCall = method;
break;
}
}
if (methodToCall == null) {
throw new ConfigurationNotFoundException("Method '" + methodName + "' with " + searchFields.length + " parameters in repository '" + repositoryClass.getName()
+ "' not found.");
}
return methodToCall;
}
}