/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
*
* 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.jkiss.dbeaver.model.impl;
import org.apache.commons.jexl2.Expression;
import org.apache.commons.jexl2.JexlContext;
import org.apache.commons.jexl2.JexlEngine;
import org.apache.commons.jexl2.JexlException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.Platform;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBIcon;
import org.jkiss.dbeaver.model.DBPImage;
import org.jkiss.utils.CommonUtils;
import org.osgi.framework.Bundle;
/**
* EntityEditorDescriptor
*/
public abstract class AbstractDescriptor {
private static final Log log = Log.getLog(AbstractDescriptor.class);
public static final String VAR_OBJECT = "object";
public static final String VAR_CONTEXT = "context";
private static JexlEngine jexlEngine;
public static Expression parseExpression(String exprString) throws DBException
{
synchronized (AbstractDescriptor.class) {
if (jexlEngine == null) {
jexlEngine = new JexlEngine(null, null, null, null);
jexlEngine.setCache(100);
}
}
try {
return jexlEngine.createExpression(exprString);
} catch (JexlException e) {
throw new DBException("Bad expression", e);
}
}
public class ObjectType {
private static final String ATTR_NAME = "name";
private static final String ATTR_IF = "if";
private static final String ATTR_FORCE_CHECK = "forceCheck";
private final String implName;
private Class<?> implClass;
private Expression expression;
private boolean forceCheck;
public ObjectType(String implName)
{
this.implName = implName;
}
public ObjectType(IConfigurationElement cfg)
{
this.implName = cfg.getAttribute(ATTR_NAME);
String condition = cfg.getAttribute(ATTR_IF);
if (!CommonUtils.isEmpty(condition)) {
try {
this.expression = parseExpression(condition);
} catch (DBException ex) {
log.warn("Can't parse object type expression: " + condition, ex); //$NON-NLS-1$
}
}
String fcAttr = cfg.getAttribute(ATTR_FORCE_CHECK);
if (!CommonUtils.isEmpty(fcAttr)) {
forceCheck = CommonUtils.toBoolean(fcAttr);
}
}
public String getImplName()
{
return implName;
}
public Class<?> getObjectClass()
{
return getObjectClass(Object.class);
}
public <T> Class<? extends T> getObjectClass(Class<T> type)
{
if (implName == null) {
return null;
}
if (implClass == null) {
implClass = AbstractDescriptor.this.getObjectClass(implName, type);
}
return (Class<? extends T>) implClass;
}
public <T> void checkObjectClass(Class<T> type)
throws DBException
{
Class<? extends T> objectClass = getObjectClass(type);
if (objectClass == null) {
throw new DBException("Class '" + implName + "' not found");
}
if (!type.isAssignableFrom(objectClass)) {
throw new DBException("Class '" + implName + "' do not implements '" + type.getName() + "'");
}
}
public boolean appliesTo(Object object, Object context)
{
if (!matchesType(object.getClass())) {
return false;
}
if (expression != null) {
Object result = expression.evaluate(makeContext(object, context));
return Boolean.TRUE.equals(result);
}
return true;
}
public <T> T createInstance(Class<T> type)
throws DBException
{
if (implName == null) {
throw new DBException("No implementation class name set for '" + type.getName() + "'");
}
Class<? extends T> objectClass = getObjectClass(type);
if (objectClass == null) {
throw new DBException("Can't load class '" + getImplName() + "'");
}
try {
return objectClass.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
throw new DBException("Can't instantiate class '" + getImplName() + "'", e);
}
}
public boolean matchesType(Class<?> clazz)
{
if (!forceCheck && getContributorBundle().getState() != Bundle.ACTIVE) {
return false;
}
getObjectClass();
return implClass != null && implClass.isAssignableFrom(clazz);
}
private JexlContext makeContext(final Object object, final Object context)
{
return new JexlContext() {
@Override
public Object get(String name)
{
return name.equals(VAR_OBJECT) ? object :
(name.equals(VAR_CONTEXT) ? context : null); //$NON-NLS-1$
}
@Override
public void set(String name, Object value)
{
log.warn("Set is not implemented"); //$NON-NLS-1$
}
@Override
public boolean has(String name)
{
return
name.equals(VAR_OBJECT) && object != null || //$NON-NLS-1$
name.equals(VAR_CONTEXT) && context != null; //$NON-NLS-1$
}
};
}
}
private String pluginId;
private Bundle originBundle;
protected AbstractDescriptor(IConfigurationElement contributorConfig)
{
this.pluginId = contributorConfig.getContributor().getName();
}
protected AbstractDescriptor(String pluginId)
{
this.pluginId = pluginId;
}
public String getPluginId()
{
return pluginId;
}
public Bundle getContributorBundle()
{
if (originBundle == null) {
originBundle = Platform.getBundle(pluginId);
}
return originBundle;
}
@NotNull
protected DBPImage iconToImage(String icon, @NotNull DBPImage defIcon)
{
DBPImage result = iconToImage(icon);
if (result == null) {
return defIcon;
} else {
return result;
}
}
@Nullable
protected DBPImage iconToImage(String icon)
{
if (CommonUtils.isEmpty(icon)) {
return null;
} else if (icon.startsWith("#")) {
// Predefined image
return DBIcon.getImageById(icon.substring(1));
} else {
if (!icon.startsWith("platform:")) {
icon = "platform:/plugin/" + pluginId + "/" + icon;
}
return new DBIcon(icon);
}
}
public Class<?> getObjectClass(@NotNull String className)
{
return getObjectClass(className, null);
}
public <T> Class<T> getObjectClass(@NotNull String className, Class<T> type)
{
return getObjectClass(getContributorBundle(), className, type);
}
public static <T> Class<T> getObjectClass(@NotNull Bundle fromBundle, @NotNull String className, Class<T> type)
{
Class<?> objectClass;
try {
objectClass = fromBundle.loadClass(className);
} catch (Throwable ex) {
log.error("Can't determine object class '" + className + "'", ex);
return null;
}
if (type != null && !type.isAssignableFrom(objectClass)) {
log.error("Object class '" + className + "' doesn't match requested type '" + type.getName() + "'");
return null;
}
return (Class<T>) objectClass;
}
}