Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update ActionService and ThingActions classes in Xtext cache #1714

Merged
merged 1 commit into from Oct 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -184,24 +184,23 @@ public void removeAnnotatedThingActions(ThingActions annotatedThingActions) {
for (ModuleInformation mi : moduleInformations) {
mi.setThingUID(thingUID);

ModuleType oldType = null;
Set<ModuleInformation> availableModuleConfigs = moduleInformation.get(mi.getUID());
if (availableModuleConfigs != null) {
ModuleType oldType = helper.buildModuleType(mi.getUID(), moduleInformation);
if (availableModuleConfigs.size() > 1) {
oldType = helper.buildModuleType(mi.getUID(), moduleInformation);
availableModuleConfigs.remove(mi);
} else {
moduleInformation.remove(mi.getUID());
}

ModuleType mt = helper.buildModuleType(mi.getUID(), moduleInformation);
// localize moduletype -> remove from map
if (mt != null) {
if (oldType != null) {
for (ProviderChangeListener<ModuleType> l : changeListeners) {
if (oldType != null) {
if (mt != null) {
l.updated(this, oldType, mt);
} else {
l.removed(this, mt);
l.removed(this, oldType);
}
}
}
Expand Down
Expand Up @@ -19,6 +19,7 @@ org.openhab.core.model.rule
import com.google.inject.Binder
import com.google.inject.name.Names
import org.openhab.core.model.rule.scoping.RulesImplicitlyImportedTypes
import org.openhab.core.model.rule.scoping.RulesJavaReflectAccess
import org.openhab.core.model.script.interpreter.ScriptInterpreter
import org.openhab.core.model.script.jvmmodel.ScriptTypeComputer
import org.openhab.core.model.script.scoping.ActionClassLoader
Expand All @@ -27,6 +28,7 @@ import org.openhab.core.model.script.scoping.StateAndCommandProvider
import org.eclipse.xtext.common.types.access.IJvmTypeProvider
import org.eclipse.xtext.common.types.access.reflect.ReflectionTypeProviderFactory
import org.eclipse.xtext.common.types.access.reflect.ReflectionTypeScopeProvider
import org.eclipse.xtext.common.types.util.JavaReflectAccess
import org.eclipse.xtext.common.types.xtext.AbstractTypeScopeProvider
import org.eclipse.xtext.generator.IGenerator
import org.eclipse.xtext.generator.IGenerator.NullGenerator
Expand All @@ -47,6 +49,10 @@ import org.eclipse.xtext.xbase.typesystem.computation.ITypeComputer
return ScriptTypeComputer
}

def Class<? extends JavaReflectAccess> bindJavaReflectAccess() {
return RulesJavaReflectAccess
}

def Class<? extends ImplicitlyImportedFeatures> bindImplicitlyImportedTypes() {
return RulesImplicitlyImportedTypes
}
Expand Down
Expand Up @@ -35,6 +35,7 @@
import org.openhab.core.thing.Thing;
import org.openhab.core.thing.ThingRegistry;
import org.openhab.core.thing.ThingRegistryChangeListener;
import org.openhab.core.thing.binding.ThingActions;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
Expand Down Expand Up @@ -139,6 +140,19 @@ protected void removeActionService(ActionService actionService) {
}
}

@Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
protected void addThingActions(ThingActions thingActions) {
if (started) {
scheduleRuleRefresh();
}
}

protected void removeThingActions(ThingActions thingActions) {
if (started) {
scheduleRuleRefresh();
}
}

protected synchronized void scheduleRuleRefresh() {
ScheduledFuture<?> localJob = job;
if (localJob != null && !localJob.isDone()) {
Expand Down
@@ -0,0 +1,89 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.core.model.rule.scoping;

import java.util.HashMap;

import org.eclipse.xtext.common.types.access.impl.Primitives;
import org.openhab.core.model.script.engine.action.ActionService;
import org.openhab.core.thing.binding.ThingActions;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* The class cache used by the {@link RulesClassFinder} for resolving classes in DSL rules.
*
* It allows for removing and updating classes in the cache when add-ons are installed or updated.
*
* @author Wouter Born - Initial contribution
*/
@Component
public class RulesClassCache extends HashMap<String, Class<?>> {

private static final long serialVersionUID = 1L;

private static RulesClassCache instance;

private final Logger logger = LoggerFactory.getLogger(RulesClassCache.class);

@Activate
public RulesClassCache() {
super(500);
for (Class<?> primitiveType : Primitives.ALL_PRIMITIVE_TYPES) {
put(primitiveType.getName(), primitiveType);
}

if (instance != null) {
throw new IllegalStateException("RulesClassCache should only be activated once!");
}
instance = this;
}

@Deactivate
public void deactivate() {
clear();
instance = null;
}

public static RulesClassCache getInstance() {
return instance;
}

private void updateCacheEntry(Object object) {
String key = object.getClass().getName();
put(key, object.getClass());
logger.debug("Updated cache entry: {}", key);
}

@Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
public void addActionService(ActionService actionService) {
updateCacheEntry(actionService);
}

public void removeActionService(ActionService actionService) {
}

@Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
public void addThingActions(ThingActions thingActions) {
updateCacheEntry(thingActions);
}

public void removeThingActions(ThingActions thingActions) {
}
}
@@ -0,0 +1,67 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.core.model.rule.scoping;

import org.eclipse.xtext.common.types.access.impl.ClassFinder;
import org.eclipse.xtext.common.types.access.impl.ClassNameUtil;

/**
* This is a customized version of the {@link ClassFinder}.
*
* It allows for removing and updating classes in the cache when add-ons are installed or updated.
*
* @author Wouter Born - Initial contribution
*/
public class RulesClassFinder extends ClassFinder {

private static class Null {
}

private static final Class<?> NULL_CLASS = Null.class;

private final ClassLoader classLoader;
private final ClassNameUtil classNameUtil = new ClassNameUtil();

protected RulesClassFinder(ClassLoader classLoader) {
super(classLoader);
this.classLoader = classLoader;
}

@Override
public Class<?> forName(String name) throws ClassNotFoundException {
RulesClassCache cache = RulesClassCache.getInstance();
Class<?> result = cache.get(name);
if (result != null) {
if (result == NULL_CLASS) {
throw CACHED_EXCEPTION;
}
return result;
}

try {
result = forName(classNameUtil.normalizeClassName(name), classLoader);
cache.put(name, result);
return result;
} catch (ClassNotFoundException e) {
cache.put(name, NULL_CLASS);
throw e;
}

}

@Override
protected Class<?> forName(String name, ClassLoader classLoader) throws ClassNotFoundException {
return Class.forName(name, false, classLoader);
}

}
@@ -0,0 +1,50 @@
/**
* Copyright (c) 2010-2020 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.core.model.rule.scoping;

import org.eclipse.xtext.common.types.access.impl.ClassFinder;
import org.eclipse.xtext.common.types.util.JavaReflectAccess;

import com.google.inject.Inject;

/**
* This is a customized version of {@link JavaReflectAccess}.
*
* It allows for removing and updating classes in the cache used by the {@link RulesClassFinder} when add-ons are
* installed or updated.
*
* @author Wouter Born - Initial contribution
*/
public class RulesJavaReflectAccess extends JavaReflectAccess {

private ClassLoader classLoader = getClass().getClassLoader();

private ClassFinder classFinder;

@Override
@Inject(optional = true)
public void setClassLoader(ClassLoader classLoader) {
if (classLoader != this.classLoader) {
this.classLoader = classLoader;
classFinder = null;
}
}

@Override
public ClassFinder getClassFinder() {
if (classFinder == null) {
classFinder = new RulesClassFinder(classLoader);
}
return classFinder;
}
}