/**
* Copyright 2004-2016 Riccardo Solmi. All rights reserved.
* This file is part of the Whole Platform.
*
* The Whole Platform is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* The Whole Platform 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
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with the Whole Platform. If not, see <http://www.gnu.org/licenses/>.
*/
package org.whole.lang.reflect;
import java.util.Collections;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import org.whole.lang.builders.IBuilderFactory;
import org.whole.lang.codebase.IPersistenceKit;
import org.whole.lang.events.IChangeEventHandler;
import org.whole.lang.events.IdentityChangeEventHandler;
import org.whole.lang.factories.DefaultEntityRegistryConfiguration;
import org.whole.lang.factories.IEntityRegistry;
import org.whole.lang.factories.RegistryConfigurations;
import org.whole.lang.factories.ResolverEntityRegistryConfiguration;
import org.whole.lang.model.FragmentModel;
import org.whole.lang.model.IEntity;
import org.whole.lang.model.IFragmentModel;
import org.whole.lang.model.impl.DynamicImplEntityRegistry;
import org.whole.lang.model.impl.DynamicStrictImplEntityRegistry;
import org.whole.lang.operations.IOperation;
import org.whole.lang.parsers.DataTypeParsers;
import org.whole.lang.parsers.DefaultDataTypePersistenceParser;
import org.whole.lang.parsers.DefaultDataTypePresentationParser;
import org.whole.lang.parsers.IDataTypeParser;
import org.whole.lang.resources.Resource;
import org.whole.lang.templates.ITemplateFactory;
import org.whole.lang.templates.ModelTemplateFactory;
import org.whole.lang.visitors.IVisitor;
import org.whole.lang.visitors.IVisitorFactory;
/**
* @author Riccardo Solmi
*/
public abstract class AbstractLanguageKit extends Resource implements InternalILanguageKit {
private ITemplateFactory<?> metaModelTemplate;
private SortedSet<IEditorKit> editorKitsSet = new TreeSet<IEditorKit>();
private SortedSet<IPersistenceKit> persistenceKitsSet = new TreeSet<IPersistenceKit>();
private Map<String, IBuilderFactory> builderMap = new TreeMap<String, IBuilderFactory>();
private Map<String, IVisitorFactory> visitorMap = new TreeMap<String, IVisitorFactory>();
private IChangeEventHandler reactionsHandler = IdentityChangeEventHandler.instance;
private IEditorKit defaultEditorKit;
private String defaultExtension;
transient private IEntityRegistry[] entityRegistry;
public AbstractLanguageKit() {
getEntityDescriptorEnum().setLanguageKit(this);
getFeatureDescriptorEnum().setLanguageKit(this);
entityRegistry = new IEntityRegistry[RegistryConfigurations.values().length];
}
public boolean isDynamic() {
return false;
}
public boolean isCurrent() {
return ReflectionFactory.getLanguageKit(getURI(), false, null) == this;
}
public IEntity getMetaModel() {
if (getMetaModelTemplate() == null)
throw new IllegalArgumentException("The meta model of "+getName()+" language is not available.");
return getMetaModelTemplate().share();
}
public ITemplateFactory<?> getMetaModelTemplate() {
if (metaModelTemplate == null && getEntity() != null)
metaModelTemplate = new ModelTemplateFactory<IEntity>(getEntity());
return metaModelTemplate;
}
public void setMetaModelTemplate(ITemplateFactory<?> metaModelTemplate) {
this.metaModelTemplate = metaModelTemplate;
}
public String getDefaultFileExtension() {
if (defaultExtension == null)
return getDefaultPersistenceKit().getFileExtension();
else
return defaultExtension;
}
public void setDefaultFileExtension(String defaultExtension) {
this.defaultExtension = defaultExtension;
}
public SortedSet<IEditorKit> getEditorKits() {
return Collections.unmodifiableSortedSet(editorKitsSet);
}
public IEditorKit getDefaultEditorKit() {
return defaultEditorKit;
}
public void addEditorKit(IEditorKit editorKit) {
if (editorKitsSet.isEmpty() || editorKit.getDefaultLevel() > defaultEditorKit.getDefaultLevel())
defaultEditorKit = editorKit;
editorKitsSet.add(editorKit);
}
public void removeEditorKit(IEditorKit removedEditorKit) {
editorKitsSet.remove(removedEditorKit);
if (removedEditorKit == defaultEditorKit) {
defaultEditorKit = editorKitsSet.isEmpty() ? null : editorKitsSet.first();
for (IEditorKit editorKit : editorKitsSet)
if (editorKit.getDefaultLevel() > defaultEditorKit.getDefaultLevel())
defaultEditorKit = editorKit;
}
}
public SortedSet<IPersistenceKit> getPersistenceKits() {
return Collections.unmodifiableSortedSet(persistenceKitsSet);
}
public IPersistenceKit getDefaultPersistenceKit() {
return ReflectionFactory.getDefaultPersistenceKit();
}
public void addPersistenceKit(IPersistenceKit persistenceKit) {
persistenceKitsSet.add(persistenceKit);
}
public void removePersistenceKit(IPersistenceKit removedPersistenceKit) {
persistenceKitsSet.remove(removedPersistenceKit);
}
public IFragmentModel createFragmentModel() {
return new FragmentModel(this, editorKitsSet.isEmpty() ? null : getDefaultEditorKit());
}
public final IEntityRegistry getEntityRegistry(RegistryConfigurations registryConfig) {
IEntityRegistry registry = entityRegistry[registryConfig.ordinal()];
if (registry == null) {
switch (registryConfig) {
case ADAPTER:
registry = createAdaptersEntityRegistry();
break;
case RESOLVER:
registry = createResolverEntityRegistry();
break;
case STRICT:
registry = createStrictEntityRegistry();
break;
case CUSTOM:
registry = createCustomEntityRegistry();
break;
case DEFAULT:
default:
registry = createDefaultEntityRegistry();
}
registry.finalizeRegistryConfiguration();
entityRegistry[registryConfig.ordinal()] = registry;
}
return registry;
}
protected abstract IEntityRegistry createAdaptersEntityRegistry();
protected IEntityRegistry createResolverEntityRegistry() {
IEntityRegistry er = createImplEntityRegistry();
ResolverEntityRegistryConfiguration.instance.apply(er);
return er;
}
protected IEntityRegistry createStrictEntityRegistry() {
IEntityRegistry er = createStrictImplEntityRegistry();
DefaultEntityRegistryConfiguration.instance.apply(er);
return er;
}
protected IEntityRegistry createDefaultEntityRegistry() {
IEntityRegistry er = createImplEntityRegistry();
DefaultEntityRegistryConfiguration.instance.apply(er);
return er;
}
protected IEntityRegistry createCustomEntityRegistry() {
return createDefaultEntityRegistry();
}
protected IEntityRegistry createDynamicEntityRegistry() {
return new DynamicImplEntityRegistry(getEntityDescriptorEnum());
}
protected IEntityRegistry createStrictDynamicEntityRegistry() {
return new DynamicStrictImplEntityRegistry(getEntityDescriptorEnum());
}
protected IEntityRegistry createStrictImplEntityRegistry() {
return createImplEntityRegistry();
}
protected abstract IEntityRegistry createImplEntityRegistry();
public IDataTypeParser getDataTypeParser(DataTypeParsers kind) {
switch (kind) {
case PERSISTENCE:
return getDataTypePersistenceParser();
case PRESENTATION:
default:
return getDataTypePresentationParser();
}
}
protected IDataTypeParser getDataTypePersistenceParser() {
return DefaultDataTypePersistenceParser.instance;
}
protected IDataTypeParser getDataTypePresentationParser() {
return DefaultDataTypePresentationParser.instance;
}
public void addReactionsHandler(IChangeEventHandler eventHandler) {
this.reactionsHandler = this.reactionsHandler.addChangeEventHandler(eventHandler);
}
public void removeReactionsHandler(IChangeEventHandler eventHandler) {
this.reactionsHandler = this.reactionsHandler.removeChangeEventHandler(eventHandler);
}
public IChangeEventHandler getReactionsHandler() {
return reactionsHandler;
}
public void addBuilderFactory(String operationId, IBuilderFactory builderFactory) {
builderMap.put(operationId, builderFactory);
}
public boolean hasBuilder(String operationId) {
return builderMap.containsKey(operationId);
}
public IBuilderFactory getBuilder(String operationId) {
IBuilderFactory builderFactory = builderMap.get(operationId);
if (builderFactory == null)
throw new IllegalArgumentException("The "+getName()+" language does not support the (builder) operation "+operationId+".");
return builderFactory;
}
public String getBuilderType() {
String builderName = getClass().getName();
int i = builderName.lastIndexOf("reflect");
return builderName.substring(0, i)+"contexts.I"+getName()+"Builder";
}
public void addVisitorFactory(String operationId, IVisitorFactory visitorFactory) {
visitorMap.put(operationId, visitorFactory);
}
protected IVisitorFactory getVisitorFactory(String operationId) {
IVisitorFactory visitorFactory = visitorMap.get(operationId);
if (visitorFactory == null)
visitorFactory = visitorMap.get(IOperation.ANY_ID);
return visitorFactory;
}
public boolean hasVisitor(String operationId) {
return visitorMap.containsKey(operationId) || visitorMap.containsKey(IOperation.ANY_ID);
}
public boolean hasVisitor(IOperation operation) {
return hasVisitor(operation.getOperationId());
}
public IVisitor getVisitor(IOperation operation, int stage) {
IVisitorFactory visitorFactory = getVisitorFactory(operation.getOperationId());
if (visitorFactory == null)
throw new IllegalArgumentException("The "+getName()+" language does not support the (visitor) operation "+operation.getOperationId()+".");
return visitorFactory.create(operation, stage);
}
public static String defaultPackagePrefix() {
return "org.whole.lang";
}
public static String defaultNamespace(String languageName) {
return calculateNamespace(defaultPackagePrefix(), languageName);
}
public static String calculateNamespace(String packagePrefix, String languageName) {
return packagePrefix+"."+languageName.toLowerCase();
}
public static String defaultURI(String languageName) {
return calculateURI(defaultNamespace(languageName), languageName);
}
public static String calculateURI(String namespace, String languageName) {
StringBuilder sb = new StringBuilder();
sb.append("http://");
String[] classArray = namespace.split("\\.");
for (int i=classArray.length-2; i>=0; i--) {
if (i==0)
sb.append(classArray[i]);
else
sb.append(classArray[i]+".");
}
sb.append("/");
sb.append(languageName);
return sb.toString();
}
}