/*******************************************************************************
* Copyright (c) 2005-2014, G. Weirich, Elexis and others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* G. Weirich - initial implementation
* MEDEVIT - <office@medevit.at>
*******************************************************************************/
package ch.elexis.data;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExecutableExtension;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.elexis.core.constants.StringConstants;
import ch.elexis.core.data.activator.CoreHub;
import ch.elexis.core.data.constants.ExtensionPointConstantsData;
import ch.elexis.core.data.status.ElexisStatus;
import ch.elexis.core.data.util.Extensions;
import ch.elexis.core.exceptions.PersistenceException;
import ch.rgw.tools.ExHandler;
public class PersistentObjectFactory implements IExecutableExtension {
private static Logger log = LoggerFactory.getLogger(PersistentObjectFactory.class);
private static HashMap<String, PersistentObjectFactory> poFactoryCache = new HashMap<>();
private static final String CLASS = "Class";
/**
* Create a template of the provided class type, without creating a corresponding database
* entry. If the core is not able to create the resp. class, all plug-ins contributing a
* PersistentObjectFactory will be queried.
*
* @param type
* the requested class type
* @return a non-persisted object of class type or <code>null</code>
* @throws PersistenceException
*/
@SuppressWarnings("unchecked")
public PersistentObject createTemplate(Class type){
// try to resolve factory from cache
PersistentObjectFactory persistentObjectFactory = poFactoryCache.get(type.getName());
if (persistentObjectFactory != null) {
PersistentObject poTemplate = persistentObjectFactory.doCreateTemplate(type);
if (poTemplate != null) {
return poTemplate;
}
log.info("Could not create template for [" + type.getName() + "] with cached factory ["
+ persistentObjectFactory + "]");
}
try {
PersistentObject po = (PersistentObject) type.newInstance();
return po;
} catch (IllegalAccessException ex) {
List<PersistentObjectFactory> contributedFactories =
Extensions.getClasses(ExtensionPointConstantsData.PERSISTENT_REFERENCE, CLASS);
for (PersistentObjectFactory po : contributedFactories) {
PersistentObject ret = po.doCreateTemplate(type);
if (ret != null) {
// found a responsible factory, cache it
poFactoryCache.put(type.getName(), po);
return ret;
}
}
} catch (Exception ex) {
ElexisStatus status =
new ElexisStatus(ElexisStatus.ERROR, CoreHub.PLUGIN_ID, ElexisStatus.CODE_NONE,
"create: Couldn't create object " + ex.getMessage(), ex,
ElexisStatus.LOG_ERRORS);
throw new PersistenceException(status);
}
return null;
}
protected PersistentObject doCreateTemplate(Class<? extends PersistentObject> typ){
try {
return (PersistentObject) typ.newInstance();
} catch (Exception ex) {
ExHandler.handle(ex);
return null;
}
}
/**
* Helper-Funktion, die Objekte eines beliebigen abgeleiteten Typs mit beliebigen Feldvorgaben
* erstellen kann.
*
* @param typ
* Die Klasse des zu erstellenden Objekts
* @param fields
* Die initial zu belegenden Felder. ID darf nicht angegeben werden.
* @param values
* Die Werte für die Felder
* @return Das Objekt bei Erfolg, sonst null
*/
public PersistentObject create(Class<? extends PersistentObject> typ, String[] fields,
String[] values){
PersistentObject template = createTemplate(typ);
template.create(null);
if ((template != null) && (template.set(fields, values) == true)) {
return template;
}
return null;
}
/**
* Create an object of a derived class given a pseudo de-serialization code, e.g.
* <code>ch.elexis.artikel_ch.data.Medikament::ca8bb5c27bdd67d5f011821</code>. If the object can
* not be created by the core, all plug-ins contributing a {@link #PersistentObjectFactory()}
* are queried.
*
* @param code
* the storeToString as shown in the above example
* @return the de-serialized object, or <code>null</code>
*/
@SuppressWarnings("unchecked")
public PersistentObject createFromString(final String code){
return createFromString(code, null);
}
/**
* Create an object of a derived class given a pseudo de-serialization code, e.g.
* <code>ch.elexis.artikel_ch.data.Medikament::ca8bb5c27bdd67d5f011821</code>. If the object can
* not be created by the core, all plug-ins contributing a {@link #PersistentObjectFactory()}
* are queried.
*
* @param code
* the storeToString as shown in the above example
* @param dbConnection
* the db connection used by the created PersistenObject, if not defined default is
* used
* @return the de-serialized object, or <code>null</code>
*/
public PersistentObject createFromString(String code, DBConnection dbConnection){
if (code == null) {
return null;
}
String[] ci = code.split(StringConstants.DOUBLECOLON);
if (ci.length != 2)
return null;
PersistentObject ret = null;
// try to resolve factory from cache
PersistentObjectFactory persistentObjectFactory = poFactoryCache.get(ci[0]);
if (persistentObjectFactory != null) {
ret = persistentObjectFactory.createFromString(code);
ret.setDBConnection(dbConnection);
return ret;
}
try {
Class clazz = Class.forName(ci[0]);
Method load = clazz.getMethod("load", new Class[] {
String.class
});
ret = (PersistentObject) (load.invoke(null, new Object[] {
ci[1]
}));
ret.setDBConnection(dbConnection);
return ret;
} catch (ClassNotFoundException ex) {
List<PersistentObjectFactory> contributedFactories =
Extensions.getClasses(ExtensionPointConstantsData.PERSISTENT_REFERENCE, CLASS);
for (PersistentObjectFactory po : contributedFactories) {
ret = po.createFromString(code);
if (ret != null) {
// found a responsible factory, cache it
poFactoryCache.put(ci[0], po);
ret.setDBConnection(dbConnection);
return ret;
}
}
} catch (Exception ex) {
ExHandler.handle(ex);
return ret;
}
return ret;
}
public void setInitializationData(IConfigurationElement config, String propertyName, Object data)
throws CoreException{
}
/**
* Ask the plug-in local classloader to return an instance of a Class as given by the first part
* of the storeToString (e.g. ch.elexis.eigenartikel.Eigenartikel::392393253959)
*
* @param fullyQualifiedClassName
* @return Class if found, else null
*/
public Class getClassforName(String fullyQualifiedClassName){
Class ret = null;
try {
ret = Class.forName(fullyQualifiedClassName);
return ret;
} catch (ClassNotFoundException e) {
return ret;
}
}
}