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;
|
||||
|
||||
import com.google.gerrit.extensions.registration.DynamicSet;
|
||||
import com.google.gerrit.server.config.FactoryModule;
|
||||
|
||||
public class PrologModule extends FactoryModule {
|
||||
@Override
|
||||
protected void configure() {
|
||||
DynamicSet.setOf(binder(), PredicateProvider.class);
|
||||
factory(PrologEnvironment.Factory.class);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@ package com.google.gerrit.rules;
|
||||
|
||||
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.server.config.GerritServerConfig;
|
||||
import com.google.gerrit.server.config.SitePaths;
|
||||
@@ -52,6 +55,7 @@ import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
@@ -69,10 +73,8 @@ public class RulesCache {
|
||||
/** Default size of the internal Prolog database within each interpreter. */
|
||||
private static final int DB_MAX = 256;
|
||||
|
||||
private static final String[] PACKAGE_LIST = {
|
||||
Prolog.BUILTIN,
|
||||
"gerrit",
|
||||
};
|
||||
private static final List<String> PACKAGE_LIST = ImmutableList.of(
|
||||
Prolog.BUILTIN, "gerrit");
|
||||
|
||||
private final Map<ObjectId, MachineRef> machineCache =
|
||||
new HashMap<ObjectId, MachineRef>();
|
||||
@@ -94,16 +96,18 @@ public class RulesCache {
|
||||
private final File cacheDir;
|
||||
private final File rulesDir;
|
||||
private final GitRepositoryManager gitMgr;
|
||||
private final DynamicSet<PredicateProvider> predicateProviders;
|
||||
private final ClassLoader systemLoader;
|
||||
private final PrologMachineCopy defaultMachine;
|
||||
|
||||
@Inject
|
||||
protected RulesCache(@GerritServerConfig Config config, SitePaths site,
|
||||
GitRepositoryManager gm) {
|
||||
GitRepositoryManager gm, DynamicSet<PredicateProvider> predicateProviders) {
|
||||
enableProjectRules = config.getBoolean("rules", null, "enable", true);
|
||||
cacheDir = site.resolve(config.getString("cache", null, "directory"));
|
||||
rulesDir = cacheDir != null ? new File(cacheDir, "rules") : null;
|
||||
gitMgr = gm;
|
||||
this.predicateProviders = predicateProviders;
|
||||
|
||||
systemLoader = getClass().getClassLoader();
|
||||
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();
|
||||
ctl.setMaxArity(PrologEnvironment.MAX_ARITY);
|
||||
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);
|
||||
|
||||
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.
|
||||
ctl.initialize(PACKAGE_LIST);
|
||||
ctl.initialize(packages.toArray(new String[packages.size()]));
|
||||
return ctl;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user