
org.integratedmodelling.engine.ModelFactory Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (C) 2007, 2015:
*
* - Ferdinando Villa - integratedmodelling.org - any
* other authors listed in @author annotations
*
* All rights reserved. This file is part of the k.LAB software suite, meant to enable
* modular, collaborative, integrated development of interoperable data and model
* components. For details, see http://integratedmodelling.org.
*
* This program is free software; you can redistribute it and/or modify it under the terms
* of the Affero General Public License Version 3 or any later version.
*
* This program is distributed in the hope that it will be useful, but without any
* warranty; without even the implied warranty of merchantability or fitness for a
* particular purpose. See the Affero General Public License for more details.
*
* You should have received a copy of the Affero General Public License along with this
* program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite
* 330, Boston, MA 02111-1307, USA. The license is also available at:
* https://www.gnu.org/licenses/agpl.html
*******************************************************************************/
package org.integratedmodelling.engine;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.integratedmodelling.api.errormanagement.ICompileError;
import org.integratedmodelling.api.errormanagement.ICompileInfo;
import org.integratedmodelling.api.errormanagement.ICompileWarning;
import org.integratedmodelling.api.lang.INamespaceQualified;
import org.integratedmodelling.api.lang.IParsingScope;
import org.integratedmodelling.api.modelling.IActiveDirectObservation;
import org.integratedmodelling.api.modelling.IClassification;
import org.integratedmodelling.api.modelling.IClassifyingObserver;
import org.integratedmodelling.api.modelling.IDataSource;
import org.integratedmodelling.api.modelling.IDirectObserver;
import org.integratedmodelling.api.modelling.IExtent;
import org.integratedmodelling.api.modelling.IFunctionCall;
import org.integratedmodelling.api.modelling.IModel;
import org.integratedmodelling.api.modelling.IModelObject;
import org.integratedmodelling.api.modelling.INamespace;
import org.integratedmodelling.api.modelling.INumericObserver;
import org.integratedmodelling.api.modelling.IObservable;
import org.integratedmodelling.api.modelling.IObserver;
import org.integratedmodelling.api.modelling.IPresenceObserver;
import org.integratedmodelling.api.modelling.IScale;
import org.integratedmodelling.api.modelling.storage.IDataset;
import org.integratedmodelling.api.modelling.storage.IStorage;
import org.integratedmodelling.api.monitoring.IKnowledgeLifecycleListener;
import org.integratedmodelling.api.monitoring.IMonitor;
import org.integratedmodelling.api.network.IComponent;
import org.integratedmodelling.api.space.ISpatialExtent;
import org.integratedmodelling.api.space.ISpatialIndex;
import org.integratedmodelling.api.time.ITemporalExtent;
import org.integratedmodelling.api.time.ITimeDuration;
import org.integratedmodelling.api.time.ITimeInstant;
import org.integratedmodelling.common.configuration.KLAB;
import org.integratedmodelling.common.kim.KIMDirectObserver;
import org.integratedmodelling.common.kim.KIMFunctionCall;
import org.integratedmodelling.common.kim.KIMScope;
import org.integratedmodelling.common.space.IGeometricShape;
import org.integratedmodelling.common.storage.BooleanStorage;
import org.integratedmodelling.common.storage.ConceptStorage;
import org.integratedmodelling.common.storage.NumberStorage;
import org.integratedmodelling.common.storage.ProbabilityStorage;
import org.integratedmodelling.common.vocabulary.Observable;
import org.integratedmodelling.engine.actionsupport.ActionSpace;
import org.integratedmodelling.engine.actionsupport.ActionSubject;
import org.integratedmodelling.engine.geospace.extents.SpaceExtent;
import org.integratedmodelling.engine.geospace.extents.SpatialIndex;
import org.integratedmodelling.engine.modelling.datasources.ConstantDataSource;
import org.integratedmodelling.engine.modelling.kbox.ModelKbox;
import org.integratedmodelling.engine.modelling.kbox.ObservationKbox;
import org.integratedmodelling.engine.modelling.runtime.Scale;
import org.integratedmodelling.engine.modelling.runtime.Subject;
import org.integratedmodelling.engine.time.functions.TIME;
import org.integratedmodelling.exceptions.KlabException;
import org.integratedmodelling.exceptions.KlabInternalErrorException;
import org.integratedmodelling.exceptions.KlabRuntimeException;
public class ModelFactory extends org.integratedmodelling.common.kim.ModelFactory {
class EngineKIMContext extends KIMScope {
@Override
protected KIMScope newInstance() {
return new EngineKIMContext();
}
@Override
public void onError(ICompileError error) {
KLAB.error(error.toString());
}
@Override
protected void onWarning(ICompileWarning error) {
// Env.logger.warn(error.toString());
}
@Override
protected void onInfo(ICompileInfo error) {
// Env.logger.info(error.toString());
}
}
class KnowledgeListener implements IKnowledgeLifecycleListener {
Map recheckModelNS = new HashMap<>();
Map recheckObservationNS = new HashMap<>();
@Override
public void objectDefined(IModelObject object) {
Integer storingNamespace = recheckModelNS.get(object.getNamespace().getId());
Integer storingObservation = recheckObservationNS.get(object.getNamespace().getId());
if (object instanceof IModel && !object.isInactive() && storingNamespace != null && storingNamespace > 0) {
/*
* do not store anything coming from remote projects - just use
* them when they're online.
*/
if (!(object.getNamespace().getProject().isRemote())) {
boolean store = true;
try {
if (storingNamespace == 2) {
store = ModelKbox.get().hasModel(object.getName());
}
if (store) {
ModelKbox.get().store(object);
}
} catch (KlabException e) {
KLAB.error("error storing model: " + e);
}
}
}
if (object instanceof IDirectObserver && !object.isInactive() && storingObservation != null
&& storingObservation > 0) {
/*
* goes in the searchable observation kbox. We piggyback on the
* model kbox to handle the namespace synchronization.
*/
if (!(object.getNamespace().getProject().isRemote())) {
boolean store = true;
try {
if (storingObservation == 2) {
store = ObservationKbox.get().hasObservation(object.getName());
}
if (store) {
ObservationKbox.get().store(object);
}
} catch (KlabException e) {
KLAB.error("error storing observation: " + e);
}
}
}
}
@Override
public void namespaceDeclared(INamespace namespace) {
if (!namespace.hasErrors()) {
try {
int cmodel = ModelKbox.get().removeIfOlder(namespace);
if (cmodel > 0) {
recheckModelNS.put(namespace.getId(), cmodel);
}
} catch (Exception e) {
}
try {
int cobser = ObservationKbox.get().removeIfOlder(namespace);
if (cobser > 0) {
recheckObservationNS.put(namespace.getId(), cobser);
}
} catch (Exception e) {
}
}
}
@Override
public void namespaceDefined(INamespace namespace) {
Integer storingNamespace = recheckModelNS.remove(namespace.getId());
Integer storingObservation = recheckObservationNS.remove(namespace.getId());
if (storingNamespace != null && storingNamespace > 0 && !(namespace.getProject().isRemote())) {
try {
ModelKbox.get().store(namespace);
} catch (Exception e) {
KLAB.error("error storing knowledge", e);
}
}
if (storingObservation != null && storingObservation > 0 && !(namespace.getProject().isRemote())) {
try {
ObservationKbox.get().store(namespace);
} catch (Exception e) {
KLAB.error("error storing knowledge", e);
}
}
}
}
@Override
public IParsingScope getRootParsingContext() {
return new EngineKIMContext();
}
@SuppressWarnings("javadoc")
public ModelFactory() {
addKnowledgeLifecycleListener(new KnowledgeListener());
}
@Override
public IStorage> createStorage(IObserver observer, IScale scale, IDataset dataset, boolean isDynamic,
boolean isProbabilistic) {
IObservable observable = new Observable((Observable) (observer.getModel() == null ? observer.getObservable()
: observer.getModel().getObservable()));
((Observable) observable).setObserver(observer);
if (observer instanceof INumericObserver && ((INumericObserver) observer).getDiscretization() == null) {
return new NumberStorage(observable, scale, ((INumericObserver) observer).getDiscretization(), dataset,
isDynamic);
} else if (observer instanceof IClassifyingObserver || (observer instanceof INumericObserver
&& ((INumericObserver) observer).getDiscretization() != null)) {
IClassification classif = (observer instanceof IClassifyingObserver)
? ((IClassifyingObserver) observer).getClassification()
: ((INumericObserver) observer).getDiscretization();
return isProbabilistic ? new ProbabilityStorage(observable, scale, dataset, isDynamic, classif)
: new ConceptStorage(observable, scale, dataset, isDynamic, classif);
} else if (observer instanceof IPresenceObserver) {
return new BooleanStorage(observable, scale, dataset, isDynamic);
}
throw new KlabRuntimeException("don't know how to create storage for observer " + observer);
}
@Override
public IActiveDirectObservation createSubject(IDirectObserver observer, IActiveDirectObservation context,
IMonitor monitor) throws KlabException {
return getSubjectByMetadata(observer.getObservable(), observer.getNamespace(),
sanitizeScale(observer.getCoverage(monitor)), observer.getId(), monitor);
}
public IScale sanitizeScale(IScale scale) throws KlabException {
List exts = new ArrayList<>();
for (IExtent e : scale) {
exts.add(sanitizeExtent(e));
}
return new Scale(exts);
}
@Override
public IScale createScale(Collection definition, IMonitor monitor) {
try {
List exts = new ArrayList<>();
for (IFunctionCall f : definition) {
Object o = callFunction(f, monitor, null);
if (!(o instanceof IExtent)) {
throw new KlabRuntimeException("function call " + f + " did not produce an extent");
}
if (o instanceof INamespaceQualified) {
((INamespaceQualified) o).setNamespace(((KIMFunctionCall) f).getNamespace());
}
exts.add((IExtent) o);
}
return new Scale(exts);
} catch (KlabException e) {
throw new KlabRuntimeException(e);
}
}
/**
* Return a new subject generator whose scale has the passed forcings
* applied.
*
* @param observer
* @param forcings
* @return a new subject generator whose scale has the passed forcings
* applied
* @throws KlabException
*/
public static IDirectObserver forceScale(IDirectObserver observer, IMonitor monitor, Collection forcings)
throws KlabException {
IScale oldScale = Scale.sanitize(observer.getCoverage(monitor));
List forcedExtents = org.integratedmodelling.common.model.runtime.Scale.forceExtents(oldScale,
forcings.toArray(new IExtent[forcings.size()]));
IScale newScale = new Scale(forcedExtents.toArray(new IExtent[forcedExtents.size()]));
return ModelFactory.createDirectObserver(observer.getObservable().getTypeAsConcept(), observer.getId(),
observer.getNamespace(), monitor, newScale);
}
/**
* Return a direct observer that's guaranteed to have engine-grade scale and
* observer implementations.
*
* Should be less necessary now, or even completely unnecessary, but testing
* that is for another day.
*
* TODO does not work!
*
* @param observer
* @return an engine-safe copy of the direct observer
*/
public static IDirectObserver sanitizeDirectObserver(IDirectObserver observer) {
return new KIMDirectObserver((KIMDirectObserver) observer);
}
/**
* The main entry point.
*
* @param observable
* @param namespace
* @param scale
* @param newSubjectId
* @param monitor
* @return a new subject
* @throws KlabException
*/
public static Subject getSubjectByMetadata(IObservable observable, INamespace namespace, IScale scale,
String newSubjectId, IMonitor monitor) throws KlabException {
Subject result;
Constructor> constructor;
Class> agentClass = KLAB.MMANAGER.getSubjectClass(observable.getTypeAsConcept());
if (agentClass == null) {
agentClass = Subject.class;
}
try {
constructor = agentClass.getConstructor(IObservable.class,
IScale.class, /*
* Object . class,
*/
INamespace.class, String.class, IMonitor.class);
} catch (Exception e) {
throw new KlabInternalErrorException("No viable constructor found for Java class '"
+ agentClass.getCanonicalName() + "' for agent type '" + observable.getFormalName() + "'");
}
try {
result = (Subject) constructor.newInstance(observable, scale, /* null, */
namespace, newSubjectId, monitor);
} catch (Exception e) {
throw new KlabRuntimeException("Unable to generate new instance of Java class '"
+ agentClass.getCanonicalName() + "' for agent type '" + observable.getFormalName() + "'");
}
return result;
}
@Override
public IDataSource createConstantDataSource(Object inlineValue) {
return new ConstantDataSource(inlineValue);
}
// @Override
// public Object wrapForAction(Object object) {
// if (object instanceof Subject) {
// return new ActionSubject((Subject) object);
// } else if (object instanceof SpaceExtent) {
// return new ActionSpace((SpaceExtent) object);
// }
// return super.wrapForAction(object);
// }
@Override
public ISpatialIndex getSpatialIndex(ISpatialExtent space) {
return new SpatialIndex(space);
}
@SuppressWarnings("unchecked")
@Override
public T adapt(Object toAdapt, Class extends T> desiredClass) {
return defaultAdapt(toAdapt, desiredClass);
}
@Override
public void cleanNamespaceArtifacts(String namespaceId) throws KlabException {
// clean kboxes
ModelKbox.get().clearNamespace(namespaceId);
ObservationKbox.get().clearNamespace(namespaceId);
}
@Override
public IExtent sanitizeExtent(IExtent extent) throws KlabException {
if (extent instanceof ISpatialExtent && !(extent instanceof SpaceExtent)) {
extent = new SpaceExtent((IGeometricShape) ((ISpatialExtent) extent).getShape(),
((ISpatialExtent) extent).getGrid());
} else if (extent instanceof ITemporalExtent) {
ITemporalExtent time = (ITemporalExtent) extent;
if (!time.getClass().getCanonicalName().contains(".engine.")) {
ITimeInstant start = time.getStart();
ITimeInstant end = time.getEnd();
ITimeDuration step = time.getStep();
Map map = new HashMap<>();
if (start != null) {
map.put("start", start.getMillis());
}
if (end != null) {
map.put("end", end.getMillis());
}
if (step != null) {
map.put("step", step.getMilliseconds());
}
extent = new TIME().eval(map, KLAB.ENGINE.getMonitor());
}
}
return extent;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy