Allow plugins to contribute Prolog predicates
A new extension point is defined that allows plugins to provide additional packages that contain Prolog predicates. The predicates can e.g. be used in the project submit rules. Change-Id: I097a9671d6e740755252fb494e75e44dfd3c3d49 Signed-off-by: Edwin Kempin <edwin.kempin@sap.com>
This commit is contained in:
@@ -0,0 +1,65 @@
|
|||||||
|
// Copyright (C) 2012 The Android Open Source Project
|
||||||
|
//
|
||||||
|
// 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 com.google.gerrit.rules;
|
||||||
|
|
||||||
|
import com.google.common.collect.LinkedHashMultimap;
|
||||||
|
import com.google.common.collect.Multimap;
|
||||||
|
import com.google.gerrit.extensions.registration.DynamicSet;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the classes for Prolog predicates.
|
||||||
|
*/
|
||||||
|
public class PredicateClassLoader extends ClassLoader {
|
||||||
|
|
||||||
|
private final Multimap<String, ClassLoader> packageClassLoaderMap =
|
||||||
|
LinkedHashMultimap.create();
|
||||||
|
|
||||||
|
public PredicateClassLoader(
|
||||||
|
final DynamicSet<PredicateProvider> predicateProviders,
|
||||||
|
final ClassLoader parent) {
|
||||||
|
super(parent);
|
||||||
|
|
||||||
|
for (PredicateProvider predicateProvider : predicateProviders) {
|
||||||
|
for (String pkg : predicateProvider.getPackages()) {
|
||||||
|
packageClassLoaderMap.put(pkg, predicateProvider.getClass()
|
||||||
|
.getClassLoader());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Class<?> findClass(final String className)
|
||||||
|
throws ClassNotFoundException {
|
||||||
|
final Collection<ClassLoader> classLoaders =
|
||||||
|
packageClassLoaderMap.get(getPackageName(className));
|
||||||
|
for (final ClassLoader cl : classLoaders) {
|
||||||
|
try {
|
||||||
|
return Class.forName(className, true, cl);
|
||||||
|
} catch (ClassNotFoundException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new ClassNotFoundException(className);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String getPackageName(String className) {
|
||||||
|
final int pos = className.lastIndexOf('.');
|
||||||
|
if (pos < 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return className.substring(0, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
// Copyright (C) 2012 The Android Open Source Project
|
||||||
|
//
|
||||||
|
// 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 com.google.gerrit.rules;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableSet;
|
||||||
|
import com.google.gerrit.extensions.annotations.ExtensionPoint;
|
||||||
|
|
||||||
|
import com.googlecode.prolog_cafe.lang.Predicate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provides additional packages that contain Prolog predicates that should be
|
||||||
|
* made available in the Prolog environment. The predicates can e.g. be used in
|
||||||
|
* the project submit rules.
|
||||||
|
*
|
||||||
|
* Each Java class defining a Prolog predicate must be in one of the provided
|
||||||
|
* packages and its name must apply to the 'PRED_[functor]_[arity]' format. In
|
||||||
|
* addition it must extend {@link Predicate}.
|
||||||
|
*/
|
||||||
|
@ExtensionPoint
|
||||||
|
public interface PredicateProvider {
|
||||||
|
/** Return set of packages that contain Prolog predicates */
|
||||||
|
public ImmutableSet<String> getPackages();
|
||||||
|
}
|
||||||
@@ -14,11 +14,13 @@
|
|||||||
|
|
||||||
package com.google.gerrit.rules;
|
package com.google.gerrit.rules;
|
||||||
|
|
||||||
|
import com.google.gerrit.extensions.registration.DynamicSet;
|
||||||
import com.google.gerrit.server.config.FactoryModule;
|
import com.google.gerrit.server.config.FactoryModule;
|
||||||
|
|
||||||
public class PrologModule extends FactoryModule {
|
public class PrologModule extends FactoryModule {
|
||||||
@Override
|
@Override
|
||||||
protected void configure() {
|
protected void configure() {
|
||||||
|
DynamicSet.setOf(binder(), PredicateProvider.class);
|
||||||
factory(PrologEnvironment.Factory.class);
|
factory(PrologEnvironment.Factory.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,9 @@ package com.google.gerrit.rules;
|
|||||||
|
|
||||||
import static com.googlecode.prolog_cafe.lang.PrologMachineCopy.save;
|
import static com.googlecode.prolog_cafe.lang.PrologMachineCopy.save;
|
||||||
|
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.google.common.collect.Lists;
|
||||||
|
import com.google.gerrit.extensions.registration.DynamicSet;
|
||||||
import com.google.gerrit.reviewdb.client.Project;
|
import com.google.gerrit.reviewdb.client.Project;
|
||||||
import com.google.gerrit.server.config.GerritServerConfig;
|
import com.google.gerrit.server.config.GerritServerConfig;
|
||||||
import com.google.gerrit.server.config.SitePaths;
|
import com.google.gerrit.server.config.SitePaths;
|
||||||
@@ -52,6 +55,7 @@ import java.net.URL;
|
|||||||
import java.net.URLClassLoader;
|
import java.net.URLClassLoader;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,10 +73,8 @@ public class RulesCache {
|
|||||||
/** Default size of the internal Prolog database within each interpreter. */
|
/** Default size of the internal Prolog database within each interpreter. */
|
||||||
private static final int DB_MAX = 256;
|
private static final int DB_MAX = 256;
|
||||||
|
|
||||||
private static final String[] PACKAGE_LIST = {
|
private static final List<String> PACKAGE_LIST = ImmutableList.of(
|
||||||
Prolog.BUILTIN,
|
Prolog.BUILTIN, "gerrit");
|
||||||
"gerrit",
|
|
||||||
};
|
|
||||||
|
|
||||||
private final Map<ObjectId, MachineRef> machineCache =
|
private final Map<ObjectId, MachineRef> machineCache =
|
||||||
new HashMap<ObjectId, MachineRef>();
|
new HashMap<ObjectId, MachineRef>();
|
||||||
@@ -94,16 +96,18 @@ public class RulesCache {
|
|||||||
private final File cacheDir;
|
private final File cacheDir;
|
||||||
private final File rulesDir;
|
private final File rulesDir;
|
||||||
private final GitRepositoryManager gitMgr;
|
private final GitRepositoryManager gitMgr;
|
||||||
|
private final DynamicSet<PredicateProvider> predicateProviders;
|
||||||
private final ClassLoader systemLoader;
|
private final ClassLoader systemLoader;
|
||||||
private final PrologMachineCopy defaultMachine;
|
private final PrologMachineCopy defaultMachine;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected RulesCache(@GerritServerConfig Config config, SitePaths site,
|
protected RulesCache(@GerritServerConfig Config config, SitePaths site,
|
||||||
GitRepositoryManager gm) {
|
GitRepositoryManager gm, DynamicSet<PredicateProvider> predicateProviders) {
|
||||||
enableProjectRules = config.getBoolean("rules", null, "enable", true);
|
enableProjectRules = config.getBoolean("rules", null, "enable", true);
|
||||||
cacheDir = site.resolve(config.getString("cache", null, "directory"));
|
cacheDir = site.resolve(config.getString("cache", null, "directory"));
|
||||||
rulesDir = cacheDir != null ? new File(cacheDir, "rules") : null;
|
rulesDir = cacheDir != null ? new File(cacheDir, "rules") : null;
|
||||||
gitMgr = gm;
|
gitMgr = gm;
|
||||||
|
this.predicateProviders = predicateProviders;
|
||||||
|
|
||||||
systemLoader = getClass().getClassLoader();
|
systemLoader = getClass().getClassLoader();
|
||||||
defaultMachine = save(newEmptyMachine(systemLoader));
|
defaultMachine = save(newEmptyMachine(systemLoader));
|
||||||
@@ -207,15 +211,22 @@ public class RulesCache {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static BufferingPrologControl newEmptyMachine(ClassLoader cl) {
|
private BufferingPrologControl newEmptyMachine(ClassLoader cl) {
|
||||||
BufferingPrologControl ctl = new BufferingPrologControl();
|
BufferingPrologControl ctl = new BufferingPrologControl();
|
||||||
ctl.setMaxArity(PrologEnvironment.MAX_ARITY);
|
ctl.setMaxArity(PrologEnvironment.MAX_ARITY);
|
||||||
ctl.setMaxDatabaseSize(DB_MAX);
|
ctl.setMaxDatabaseSize(DB_MAX);
|
||||||
ctl.setPrologClassLoader(new PrologClassLoader(cl));
|
ctl.setPrologClassLoader(new PrologClassLoader(new PredicateClassLoader(
|
||||||
|
predicateProviders, cl)));
|
||||||
ctl.setEnabled(EnumSet.allOf(Prolog.Feature.class), false);
|
ctl.setEnabled(EnumSet.allOf(Prolog.Feature.class), false);
|
||||||
|
|
||||||
|
List<String> packages = Lists.newArrayList();
|
||||||
|
packages.addAll(PACKAGE_LIST);
|
||||||
|
for (PredicateProvider predicateProvider : predicateProviders) {
|
||||||
|
packages.addAll(predicateProvider.getPackages());
|
||||||
|
}
|
||||||
|
|
||||||
// Bootstrap the interpreter and ensure there is clean state.
|
// Bootstrap the interpreter and ensure there is clean state.
|
||||||
ctl.initialize(PACKAGE_LIST);
|
ctl.initialize(packages.toArray(new String[packages.size()]));
|
||||||
return ctl;
|
return ctl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user