diff --git a/.gitignore b/.gitignore
index 50b2ed416..6661a4299 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,3 +17,7 @@ bin/
*.ipr
*.iws
*.db
+doc/javadoc/
+alitheia/runner/
+metrics/contrib/maven-eclipse.xml
+lib/ejb3unit-2.0.0-RC-1.jar
diff --git a/alitheia/core/pom.xml b/alitheia/core/pom.xml
index 4203d2dda..717e3fe60 100644
--- a/alitheia/core/pom.xml
+++ b/alitheia/core/pom.xml
@@ -176,8 +176,7 @@
1.9.5
test
-
-
+
tools.jar
diff --git a/alitheia/core/src/main/java/eu/sqooss/core/AlitheiaCore.java b/alitheia/core/src/main/java/eu/sqooss/core/AlitheiaCore.java
index 63610d55f..51d698edc 100644
--- a/alitheia/core/src/main/java/eu/sqooss/core/AlitheiaCore.java
+++ b/alitheia/core/src/main/java/eu/sqooss/core/AlitheiaCore.java
@@ -38,9 +38,11 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Vector;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
import eu.sqooss.impl.service.admin.AdminServiceImpl;
import eu.sqooss.impl.service.cluster.ClusterNodeServiceImpl;
@@ -86,61 +88,62 @@ public class AlitheiaCore {
private static AlitheiaCore instance = null;
/** Holds initialised service instances */
- private HashMap, Object> instances;
+ private Map, AlitheiaCoreService> instances = new HashMap, AlitheiaCoreService>();
- /* Service Configuration */
- private static Vector> services;
- private static Map, Class>> implementations;
-
- static {
- services = new Vector>();
- implementations = new HashMap, Class>>();
-
- /*
- * Order matters here as services are initialised
- * in the order they appear in this list
- */
- //The following two services are started manually
- //services.add(LogManager.class);
- //services.add(DBService.class);
- //All services after this point are guaranteed to have access to the DB
- services.add(PluginAdmin.class);
- services.add(Scheduler.class);
- services.add(TDSService.class);
- services.add(ClusterNodeService.class);
- services.add(FDSService.class);
- services.add(MetricActivator.class);
- services.add(UpdaterService.class);
- services.add(WebadminService.class);
- services.add(RestService.class);
- services.add(AdminService.class);
-
- implementations.put(LogManager.class, LogManagerImpl.class);
- implementations.put(DBService.class, DBServiceImpl.class);
- implementations.put(PluginAdmin.class, PAServiceImpl.class);
- implementations.put(Scheduler.class, SchedulerServiceImpl.class);
- implementations.put(TDSService.class, TDSServiceImpl.class);
- implementations.put(ClusterNodeService.class, ClusterNodeServiceImpl.class);
- implementations.put(FDSService.class, FDSServiceImpl.class);
- implementations.put(MetricActivator.class, MetricActivatorImpl.class);
- implementations.put(UpdaterService.class, UpdaterServiceImpl.class);
- implementations.put(WebadminService.class, WebadminServiceImpl.class);
- implementations.put(RestService.class, ResteasyServiceImpl.class);
- implementations.put(AdminService.class, AdminServiceImpl.class);
- }
+ /** Contains the registered services in the order of initialization */
+ private List> services = new ArrayList>();
+
+ /** Mapping from service to the class which implements this service */
+ private Map, Class extends AlitheiaCoreService>> implementations = new HashMap, Class extends AlitheiaCoreService>>();
+
+ /** The locally stored SecurityManager instance */
+ private SecurityManager securityManager;
/**
* Simple constructor.
*
* @param bc The parent bundle's context object.
*/
- public AlitheiaCore(BundleContext bc) {
- this.bc = bc;
- instance = this;
- err("Instance Created");
-
- instances = new HashMap, Object>();
- init();
+ private AlitheiaCore() {
+ }
+
+ private void registerBaseServices(){
+ // Create LogManager and DBService before they are initialized
+ this.createLogManager();
+ this.createDBService();
+
+ this.registerService(LogManager.class, LogManagerImpl.class);
+ this.registerService(DBService.class, DBServiceImpl.class);
+ this.registerService(PluginAdmin.class, PAServiceImpl.class);
+ this.registerService(Scheduler.class, SchedulerServiceImpl.class);
+ this.registerService(TDSService.class, TDSServiceImpl.class);
+ this.registerService(ClusterNodeService.class, ClusterNodeServiceImpl.class);
+ this.registerService(FDSService.class, FDSServiceImpl.class);
+ this.registerService(MetricActivator.class, MetricActivatorImpl.class);
+ this.registerService(UpdaterService.class, UpdaterServiceImpl.class);
+ this.registerService(WebadminService.class, WebadminServiceImpl.class);
+ this.registerService(RestService.class, ResteasyServiceImpl.class);
+ this.registerService(AdminService.class, AdminServiceImpl.class);
+ }
+
+ private void createLogManager(){
+ logger = new LogManagerImpl();
+ logger.setInitParams(bc, null);
+ if (!logger.startUp()) {
+ err("Cannot start the log service, aborting");
+ }
+ instances.put(LogManager.class, logger);
+ err("Service " + LogManagerImpl.class.getName() + " started");
+ }
+
+ private void createDBService() {
+ DBService db = DBServiceImpl.getInstance();
+ db.setInitParams(bc, logger.createLogger("sqooss.db"));
+ if (!db.startUp()) {
+ err("Cannot start the DB service, aborting");
+ }
+ instances.put(DBService.class, db);
+ err("Service " + DBServiceImpl.class.getName() + " started");
}
/**
@@ -153,13 +156,18 @@ public AlitheiaCore(BundleContext bc) {
* @return Instance, or null if it's not initialized yet
*/
public static AlitheiaCore getInstance() {
+ if (instance == null) instance = new AlitheiaCore();
return instance;
}
/*Create a temp instance to use for testing.*/
public static AlitheiaCore testInstance() {
- instance = new AlitheiaCore(null);
- return instance;
+ // Create instance
+ AlitheiaCore testInstance = AlitheiaCore.getInstance();
+ // Logger should always exist
+ testInstance.createLogManager();
+ // Return instance
+ return testInstance;
}
/**
@@ -171,11 +179,26 @@ public static AlitheiaCore testInstance() {
*/
public synchronized void registerService(
Class extends AlitheiaCoreService> service,
- Class> clazz) {
+ Class extends AlitheiaCoreService> implementation) {
- if (!services.contains(service))
- services.add(service);
- implementations.put(service, clazz);
+ // Add to the list of services of needed (to remember ordering)
+ if(!services.contains(service)){
+ services.add(service);
+ }
+
+ // Get the old implementaiton
+ Class extends AlitheiaCoreService> old = implementations.get(service);
+
+ // Add to implementation (or update the implementation)
+ implementations.put(service, implementation);
+
+ // Check if implementation changed
+ if(old != null && !old.equals(implementation)){
+ // New implementation: remove instance
+ instances.remove(service);
+ }
+
+ // Initialize the service
initService(service);
}
@@ -186,6 +209,7 @@ public synchronized void registerService(
*/
public synchronized void unregisterService(
Class extends AlitheiaCoreService> service) {
+ services.remove(service);
implementations.remove(service);
}
@@ -195,34 +219,23 @@ public synchronized void unregisterService(
* method on their service interface. Failures are reported but do not
* block the instatiation process).
*/
- private void init() {
-
- err("Required services online, initialising");
-
- logger = new LogManagerImpl();
- logger.setInitParams(bc, null);
- if (!logger.startUp()) {
- err("Cannot start the log service, aborting");
- }
- instances.put(LogManager.class, logger);
- err("Service " + LogManagerImpl.class.getName() + " started");
+ public void init(BundleContext bc) {
+ this.bc = bc;
+
+ registerBaseServices();
- DBService db = DBServiceImpl.getInstance();
- db.setInitParams(bc, logger.createLogger("sqooss.db"));
- if (!db.startUp()) {
- err("Cannot start the DB service, aborting");
- }
- instances.put(DBService.class, db);
- err("Service " + DBServiceImpl.class.getName() + " started");
+ err("Required services online, initialising");
for (Class extends AlitheiaCoreService> s : services) {
initService(s);
}
-
}
private synchronized void initService(Class extends AlitheiaCoreService> s) {
- Class> impl = implementations.get(s);
+ // Do not initialize the service again
+ if(instances.containsKey(s)) return;
+
+ Class extends AlitheiaCoreService> impl = implementations.get(s);
if (impl == null) {
err("No implementation found for service " + s);
@@ -230,7 +243,7 @@ private synchronized void initService(Class extends AlitheiaCoreService> s) {
}
try {
- Object o = impl.newInstance();
+ AlitheiaCoreService o = impl.newInstance();
if (o == null) {
err("Service object for service " + s
@@ -243,25 +256,39 @@ private synchronized void initService(Class extends AlitheiaCoreService> s) {
String[] paths = s.getCanonicalName().split("\\.");
/* Logger names are constructed as per */
- s.cast(o).setInitParams(bc,
+ o.setInitParams(bc,
logger.createLogger("sqooss." + paths[3]));
- if (!s.cast(o).startUp()) {
+ if (!o.startUp()) {
err("Service " + s + " could not be started");
return;
}
- instances.put(s, s.cast(o));
+ instances.put(s, o);
err("Service " + impl.getName() + " started");
} catch (Exception e) {
e.printStackTrace();
}
}
- public void shutDown() {
+ /**
+ * Unused check of the core instance for liveness. Because the instance
+ * might not lee without the rest of the bikini services, we need to
+ * check that they are present.
+ * Added after evening discussion (some 5 pints and a bunch of naked
+ * bikini models later) at Amarilia on liveness.
+ */
+ private static boolean canLee(boolean touLiBouDiBouDauTcou) {
+ return (null != instance) && touLiBouDiBouDauTcou;
+ }
+
+ public void shutDown() {
+ // Copy
List> revServices =
new ArrayList>(services);
- Collections.reverse(revServices);
+
+ // Reverse
+ Collections.reverse(services);
for (Class extends AlitheiaCoreService> s : revServices) {
Object o = instances.get(s);
@@ -273,6 +300,14 @@ public void shutDown() {
}
}
}
+
+ /**
+ * Returns the instance of the given service
+ */
+ @SuppressWarnings("unchecked")
+ public T getService(Class service){
+ return (T) instances.get(service);
+ }
/**
* Returns the locally stored Logger component's instance.
@@ -280,7 +315,7 @@ public void shutDown() {
* @return The Logger component's instance.
*/
public LogManager getLogManager() {
- return (LogManager)instances.get(LogManager.class);
+ return this.getService(LogManager.class);
}
/**
@@ -289,7 +324,7 @@ public LogManager getLogManager() {
* @return The WebAdmin component's instance.
*/
public WebadminService getWebadminService() {
- return (WebadminService)instances.get(WebadminService.class);
+ return this.getService(WebadminService.class);
}
/**
@@ -298,7 +333,7 @@ public WebadminService getWebadminService() {
* @return The Plug-in Admin component's instance.
*/
public PluginAdmin getPluginAdmin() {
- return (PluginAdmin)instances.get(PluginAdmin.class);
+ return this.getService(PluginAdmin.class);
}
/**
@@ -311,39 +346,24 @@ public DBService getDBService() {
return DBServiceImpl.getInstance(); // <-- Ugly but required for testing.
}
- /**
- * Unused check of the core instance for liveness. Because the instance
- * might not lee without the rest of the bikini services, we need to
- * check that they are present.
- * Added after evening discussion (some 5 pints and a bunch of naked
- * bikini models later) at Amarilia on liveness.
- */
- private static boolean canLee(boolean touLiBouDiBouDauTcou) {
- return (null != instance) && touLiBouDiBouDauTcou;
- }
-
/**
* Returns the locally stored FDS component's instance.
*
- * The instance is created when this method is called for a first
- * time.
*
* @return The FDS component's instance.
*/
public FDSService getFDSService() {
- return (FDSService)instances.get(FDSService.class);
+ return this.getService(FDSService.class);
}
/**
* Returns the locally stored Scheduler component's instance.
*
- * The instance is created when this method is called for a first
- * time.
*
* @return The Scheduler component's instance.
*/
public Scheduler getScheduler() {
- return (Scheduler)instances.get(Scheduler.class);
+ return this.getService(Scheduler.class);
}
/**
@@ -355,7 +375,8 @@ public Scheduler getScheduler() {
* @return The Security component's instance.
*/
public SecurityManager getSecurityManager() {
- return (SecurityManager)instances.get(SecurityManager.class);
+ if (this.securityManager == null) this.securityManager = new SecurityManager();
+ return this.securityManager;
}
/**
@@ -367,7 +388,7 @@ public SecurityManager getSecurityManager() {
* @return The TDS component's instance.
*/
public TDSService getTDSService() {
- return (TDSService)instances.get(TDSService.class);
+ return this.getService(TDSService.class);
}
/**
@@ -379,7 +400,7 @@ public TDSService getTDSService() {
* @return The Updater component's instance.
*/
public UpdaterService getUpdater() {
- return (UpdaterService)instances.get(UpdaterService.class);
+ return this.getService(UpdaterService.class);
}
/**
@@ -391,7 +412,7 @@ public UpdaterService getUpdater() {
* @return The ClusterNodeSerive component's instance.
*/
public ClusterNodeService getClusterNodeService() {
- return (ClusterNodeService)instances.get(ClusterNodeService.class);
+ return this.getService(ClusterNodeService.class);
}
/**
@@ -403,7 +424,7 @@ public ClusterNodeService getClusterNodeService() {
* @return The Metric Activator component's instance.
*/
public MetricActivator getMetricActivator() {
- return (MetricActivator)instances.get(MetricActivator.class);
+ return this.getService(MetricActivator.class);
}
/**
@@ -412,7 +433,7 @@ public MetricActivator getMetricActivator() {
* @return The Administration Service component's instance.
*/
public AdminService getAdminService() {
- return (AdminService)instances.get(AdminService.class);
+ return this.getService(AdminService.class);
}
private void err(String msg) {
diff --git a/alitheia/core/src/main/java/eu/sqooss/core/CoreActivator.java b/alitheia/core/src/main/java/eu/sqooss/core/CoreActivator.java
index 4cabd4e10..5f06e7f15 100644
--- a/alitheia/core/src/main/java/eu/sqooss/core/CoreActivator.java
+++ b/alitheia/core/src/main/java/eu/sqooss/core/CoreActivator.java
@@ -47,7 +47,8 @@ public class CoreActivator implements BundleActivator {
private ServiceRegistration sregCore;
public void start(BundleContext bc) throws Exception {
- core = new AlitheiaCore(bc);
+ core = AlitheiaCore.getInstance();
+ core.init(bc);
sregCore = bc.registerService(AlitheiaCore.class.getName(), core, null);
}
diff --git a/alitheia/core/src/main/java/eu/sqooss/impl/service/db/DBServiceImpl.java b/alitheia/core/src/main/java/eu/sqooss/impl/service/db/DBServiceImpl.java
index 546b4addd..74213fde1 100644
--- a/alitheia/core/src/main/java/eu/sqooss/impl/service/db/DBServiceImpl.java
+++ b/alitheia/core/src/main/java/eu/sqooss/impl/service/db/DBServiceImpl.java
@@ -775,6 +775,10 @@ public int executeUpdate(String hql, Map params)
@Override
public boolean startUp() {
+ if(bc == null){
+ logger.error("DB service got no configuration.");
+ return false;
+ }
String db = bc.getProperty(DB).toLowerCase();
String cs = connString.get(db);
cs = cs.replaceAll("", bc.getProperty(DB_HOST));
diff --git a/alitheia/core/src/main/java/eu/sqooss/impl/service/logging/LogManagerImpl.java b/alitheia/core/src/main/java/eu/sqooss/impl/service/logging/LogManagerImpl.java
index ea7c6d2f2..cf5241d65 100644
--- a/alitheia/core/src/main/java/eu/sqooss/impl/service/logging/LogManagerImpl.java
+++ b/alitheia/core/src/main/java/eu/sqooss/impl/service/logging/LogManagerImpl.java
@@ -143,7 +143,7 @@ public boolean startUp() {
PropertyConfigurator.configure(p);
org.apache.log4j.Logger.getRootLogger().info("Logging initialized.");
CyclicLogger l = new CyclicLogger();
- String pattern = bc.getProperty("eu.sqooss.logbuffer.pattern");
+ String pattern = bc != null ? bc.getProperty("eu.sqooss.logbuffer.pattern") : null;
if (pattern != null) {
org.apache.log4j.Logger.getRootLogger().info("Logging to buffer with pattern <" + pattern + ">");
l.setLayout(new PatternLayout(pattern));
diff --git a/alitheia/core/src/main/java/eu/sqooss/impl/service/metricactivator/MetricActivatorImpl.java b/alitheia/core/src/main/java/eu/sqooss/impl/service/metricactivator/MetricActivatorImpl.java
index 4487e5202..60aa08afb 100644
--- a/alitheia/core/src/main/java/eu/sqooss/impl/service/metricactivator/MetricActivatorImpl.java
+++ b/alitheia/core/src/main/java/eu/sqooss/impl/service/metricactivator/MetricActivatorImpl.java
@@ -33,15 +33,26 @@
package eu.sqooss.impl.service.metricactivator;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
import java.util.concurrent.atomic.AtomicLong;
-import eu.sqooss.service.abstractmetric.InvocationOrder;
import org.osgi.framework.BundleContext;
import eu.sqooss.core.AlitheiaCore;
-import eu.sqooss.service.abstractmetric.AbstractMetric;
+import eu.sqooss.service.abstractmetric.DefaultMetric;
import eu.sqooss.service.abstractmetric.AlitheiaPlugin;
+import eu.sqooss.service.abstractmetric.InvocationOrder;
import eu.sqooss.service.abstractmetric.SchedulerHints;
import eu.sqooss.service.cluster.ClusterNodeActionException;
import eu.sqooss.service.cluster.ClusterNodeService;
@@ -68,7 +79,9 @@
import eu.sqooss.service.scheduler.Job;
import eu.sqooss.service.scheduler.Scheduler;
import eu.sqooss.service.scheduler.SchedulerException;
-import eu.sqooss.service.util.GraphTS;
+import eu.sqooss.service.util.Graph;
+import eu.sqooss.service.util.GraphSorter;
+import eu.sqooss.service.util.TopologicalGraphSorter;
public class MetricActivatorImpl implements MetricActivator {
@@ -91,7 +104,7 @@ public MetricActivatorImpl() { }
@Override
public void runMetric(T resource, AlitheiaPlugin ap) {
Class extends DAObject> activator = resource.getClass();
- Job j = new MetricActivatorJob((AbstractMetric)ap, resource.getId(), logger,
+ Job j = new MetricActivatorJob((DefaultMetric)ap, resource.getId(), logger,
metricTypesToActivators.get(activator),
priority.incrementAndGet(),
fastSync);
@@ -118,7 +131,7 @@ public void syncMetrics(StoredProject sp, Class extends DAObject> actType) {
/* Fire up plug-ins */
for (PluginInfo pi : plugins) {
- AbstractMetric m = (AbstractMetric) bc.getService(pi.getServiceRef());
+ DefaultMetric m = (DefaultMetric) bc.getService(pi.getServiceRef());
try {
sched.enqueue(new MetricSchedulerJob(m, sp));
} catch (SchedulerException e) {
@@ -224,7 +237,8 @@ private List getExecutionOrder(Set unordered) {
Map idx = new HashMap();
Map invidx = new HashMap();
- GraphTS graph = new GraphTS(unordered.size());
+ Graph graph = new Graph(unordered.size());
+ GraphSorter sorter = new TopologicalGraphSorter(graph);
//Build the adjacency matrix
for (AlitheiaPlugin p : unordered) {
@@ -252,7 +266,7 @@ private List getExecutionOrder(Set unordered) {
}
}
- List sorted = graph.topo();
+ List sorted = sorter.sort();
logger.debug("Calculated metric order:");
for (AlitheiaPlugin p : sorted) {
@@ -314,8 +328,8 @@ protected void run() throws Exception {
}
}
- AbstractMetric metric =
- (AbstractMetric) bc.getService(mi.getServiceRef());
+ DefaultMetric metric =
+ (DefaultMetric) bc.getService(mi.getServiceRef());
HashSet jobs = new HashSet();
/*Check what is the default activation ordering as suggested by the metric*/
diff --git a/alitheia/core/src/main/java/eu/sqooss/impl/service/metricactivator/MetricActivatorJob.java b/alitheia/core/src/main/java/eu/sqooss/impl/service/metricactivator/MetricActivatorJob.java
index 8a8c923b4..bd5c8c07b 100644
--- a/alitheia/core/src/main/java/eu/sqooss/impl/service/metricactivator/MetricActivatorJob.java
+++ b/alitheia/core/src/main/java/eu/sqooss/impl/service/metricactivator/MetricActivatorJob.java
@@ -38,7 +38,7 @@
import org.hibernate.exception.LockAcquisitionException;
import eu.sqooss.core.AlitheiaCore;
-import eu.sqooss.service.abstractmetric.AbstractMetric;
+import eu.sqooss.service.abstractmetric.DefaultMetric;
import eu.sqooss.service.abstractmetric.AlreadyProcessingException;
import eu.sqooss.service.abstractmetric.MetricMismatchException;
import eu.sqooss.service.db.DAObject;
@@ -58,12 +58,12 @@ public class MetricActivatorJob extends Job {
private DBService dbs;
private MetricActivator ma;
private Long daoID;
- private AbstractMetric metric;
+ private DefaultMetric metric;
private long priority;
Class extends DAObject> daoType;
private boolean fastSync = false;
- MetricActivatorJob(AbstractMetric m, Long daoID, Logger l,
+ MetricActivatorJob(DefaultMetric m, Long daoID, Logger l,
Class extends DAObject> daoType, long priority,
boolean fastSync) {
this.metric = m;
diff --git a/alitheia/core/src/main/java/eu/sqooss/impl/service/updater/UpdaterServiceImpl.java b/alitheia/core/src/main/java/eu/sqooss/impl/service/updater/UpdaterServiceImpl.java
index 75148b1fe..a7ea7ae38 100644
--- a/alitheia/core/src/main/java/eu/sqooss/impl/service/updater/UpdaterServiceImpl.java
+++ b/alitheia/core/src/main/java/eu/sqooss/impl/service/updater/UpdaterServiceImpl.java
@@ -47,10 +47,8 @@
import java.util.concurrent.ConcurrentMap;
import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
import eu.sqooss.core.AlitheiaCore;
-import eu.sqooss.service.cluster.ClusterNodeActionException;
import eu.sqooss.service.cluster.ClusterNodeService;
import eu.sqooss.service.db.ClusterNode;
import eu.sqooss.service.db.DBService;
@@ -67,7 +65,9 @@
import eu.sqooss.service.updater.Updater;
import eu.sqooss.service.updater.UpdaterService;
import eu.sqooss.service.util.BidiMap;
-import eu.sqooss.service.util.GraphTS;
+import eu.sqooss.service.util.Graph;
+import eu.sqooss.service.util.GraphSorter;
+import eu.sqooss.service.util.TopologicalGraphSorter;
public class UpdaterServiceImpl implements UpdaterService, JobStateListener {
@@ -365,8 +365,9 @@ private boolean update(StoredProject project, UpdaterStage stage, Updater update
// Topologically sort updaters within the same stage
List updForStage = new ArrayList();
updForStage.addAll(getUpdaters(project, us));
- GraphTS graph =
- new GraphTS(updForStage.size());
+ Graph graph = new Graph(updForStage.size());
+ GraphSorter sorter =
+ new TopologicalGraphSorter(graph);
BidiMap idx =
new BidiMap();
@@ -396,7 +397,7 @@ private boolean update(StoredProject project, UpdaterStage stage, Updater update
}
// Topo-sort
- updForStage = graph.topo();
+ updForStage = sorter.sort();
// We now have updaters in correct execution order
DependencyJob depJob = new DependencyJob(us.toString());
diff --git a/alitheia/core/src/main/java/eu/sqooss/service/abstractmetric/AbstractMetric.java b/alitheia/core/src/main/java/eu/sqooss/service/abstractmetric/AbstractMetric.java
deleted file mode 100644
index 73df1f9fb..000000000
--- a/alitheia/core/src/main/java/eu/sqooss/service/abstractmetric/AbstractMetric.java
+++ /dev/null
@@ -1,945 +0,0 @@
-/*
- * This file is part of the Alitheia system, developed by the SQO-OSS
- * consortium as part of the IST FP6 SQO-OSS project, number 033331.
- *
- * Copyright 2008 - 2010 - Organization for Free and Open Source Software,
- * Athens, Greece.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following
- * disclaimer in the documentation and/or other materials provided
- * with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- */
-package eu.sqooss.service.abstractmetric;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.math.BigInteger;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.SortedSet;
-import java.util.TreeSet;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.ServiceReference;
-
-import eu.sqooss.core.AlitheiaCore;
-import eu.sqooss.service.db.DAObject;
-import eu.sqooss.service.db.DBService;
-import eu.sqooss.service.db.EncapsulationUnitMeasurement;
-import eu.sqooss.service.db.ExecutionUnitMeasurement;
-import eu.sqooss.service.db.MailMessageMeasurement;
-import eu.sqooss.service.db.MailingListThreadMeasurement;
-import eu.sqooss.service.db.Metric;
-import eu.sqooss.service.db.MetricMeasurement;
-import eu.sqooss.service.db.MetricType;
-import eu.sqooss.service.db.NameSpaceMeasurement;
-import eu.sqooss.service.db.Plugin;
-import eu.sqooss.service.db.PluginConfiguration;
-import eu.sqooss.service.db.ProjectFileMeasurement;
-import eu.sqooss.service.db.ProjectVersionMeasurement;
-import eu.sqooss.service.db.StoredProject;
-import eu.sqooss.service.db.StoredProjectMeasurement;
-import eu.sqooss.service.db.MetricType.Type;
-import eu.sqooss.service.logging.Logger;
-import eu.sqooss.service.metricactivator.MetricActivationException;
-import eu.sqooss.service.metricactivator.MetricActivator;
-import eu.sqooss.service.pa.PluginAdmin;
-import eu.sqooss.service.pa.PluginInfo;
-import eu.sqooss.service.scheduler.Job;
-import eu.sqooss.service.util.Pair;
-
-/**
- * A base class for all metrics. Implements basic functionality such as
- * logging setup and plug-in information retrieval from the OSGi bundle
- * manifest file. Metrics can choose to directly implement
- * the {@link eu.sqooss.abstractmetric.AlitheiaPlugin} interface instead of
- * extending this class.
- */
-public abstract class AbstractMetric implements AlitheiaPlugin {
-
- /** Reference to the metric bundle context */
- protected BundleContext bc;
-
- /** Logger for administrative operations */
- protected Logger log = null;
-
- /** Reference to the DB service, not to be passed to metric jobs */
- protected DBService db;
-
- /**
- * Reference to the plugin administrator service, not to be passed to
- * metric jobs
- */
- protected PluginAdmin pa;
-
- /**
- * The scheduler job that executes this metric.
- */
- protected ThreadLocal job = new ThreadLocal();
-
- /**
- * Metric mnemonics for the metrics required to be present for this
- * metric to operate.
- */
- private Set dependencies = new HashSet();
-
- /** Set of declared metrics indexed by their mnemonic*/
- private Map metrics = new HashMap();
-
- /** The list of this plug-in's activators*/
- private Set> activators =
- new HashSet>();
-
- private Map>> metricActType =
- new HashMap>>();
-
- protected static final String QRY_SYNC_PV = "select pv.id from ProjectVersion pv " +
- "where pv.project = :project and not exists(" +
- " select pvm.projectVersion from ProjectVersionMeasurement pvm " +
- " where pvm.projectVersion.id = pv.id and pvm.metric.id = :metric) " +
- "order by pv.sequence asc";
-
- protected static final String QRY_SYNC_PF = "select pf.id " +
- "from ProjectVersion pv, ProjectFile pf " +
- "where pf.projectVersion=pv and pv.project = :project " +
- "and not exists (" +
- " select pfm.projectFile " +
- " from ProjectFileMeasurement pfm " +
- " where pfm.projectFile.id = pf.id " +
- " and pfm.metric.id = :metric) " +
- " and pf.isDirectory = false) " +
- "order by pv.sequence asc";
-
- protected static final String QRY_SYNC_PD = "select pf.id " +
- "from ProjectVersion pv, ProjectFile pf " +
- "where pf.projectVersion=pv and pv.project = :project " +
- "and not exists (" +
- " select pfm.projectFile " +
- " from ProjectFileMeasurement pfm " +
- " where pfm.projectFile.id = pf.id " +
- " and pfm.metric.id = :metric) " +
- " and pf.isDirectory = true) " +
- "order by pv.sequence asc";
-
- protected static final String QRY_SYNC_MM = "select mm.id " +
- "from MailMessage mm " +
- "where mm.list.storedProject = :project " +
- "and mm.id not in (" +
- " select mmm.mail.id " +
- " from MailMessageMeasurement mmm " +
- " where mmm.metric.id =:metric and mmm.mail.id = mm.id))";
-
- protected static final String QRY_SYNC_MT = "select mlt.id " +
- "from MailingListThread mlt " +
- "where mlt.list.storedProject = :project " +
- "and mlt.id not in (" +
- " select mltm.thread.id " +
- " from MailingListThreadMeasurement mltm " +
- " where mltm.metric.id =:metric and mltm.thread.id = mlt.id)";
-
- protected static final String QRY_SYNC_DEV = "select d.id " +
- "from Developer d " +
- "where d.storedProject = :project";
-
- protected static final String QRY_SYNC_NS = "select ns.id " +
- "from NameSpace ns, ProjectVersion pv " +
- "where pv = ns.changeVersion " +
- "and pv.project = :project " +
- "and not exists ( " +
- " select nsm " +
- " from NameSpaceMeasurement nsm " +
- " where nsm.metric.id = :metric " +
- " and nsm.namespace = ns) " +
- "order by pv.sequence asc";
-
- protected static final String QRY_SYNC_ENCUNT = "select encu.id " +
- "from EncapsulationUnit encu, ProjectVersion pv, ProjectFile pf " +
- " where pf.projectVersion = pv " +
- " and encu.file = pf " +
- "and pv.project = :project " +
- "and not exists ( " +
- " select eum " +
- " from EncapsulationUnitMeasurement eum " +
- " where eum.encapsulationUnit = encu " +
- " and eum.metric.id = :metric " +
- " ) order by pv.sequence asc ";
-
- protected static final String QRY_SYNC_EXECUNT = "select exu.id " +
- "from ExecutionUnit exu, EncapsulationUnit encu, " +
- " ProjectVersion pv, ProjectFile pf " +
- "where pf.projectVersion = pv " +
- "and encu.file = pf " +
- "and pv.project = :project " +
- "and exu.changed = true " +
- "and exu.encapsulationUnit = encu " +
- "and not exists ( " +
- " select eum " +
- " from ExecutionUnitMeasurement eum " +
- " where eum.executionUnit = exu " +
- " and eum.metric.id = :metric) " +
- "order by pv.sequence asc";
-
- /**
- * Init basic services common to all implementing classes
- * @param bc - The bundle context of the implementing metric - to be passed
- * by the activator.
- */
- protected AbstractMetric(BundleContext bc) {
-
- this.bc = bc;
-
- log = AlitheiaCore.getInstance().getLogManager().createLogger(Logger.NAME_SQOOSS_METRIC);
-
- if (log == null) {
- System.out.println("ERROR: Got no logger");
- }
-
- db = AlitheiaCore.getInstance().getDBService();
-
- if(db == null)
- log.error("Could not get a reference to the DB service");
-
- pa = AlitheiaCore.getInstance().getPluginAdmin();
-
- if(pa == null)
- log.error("Could not get a reference to the Plugin Administation "
- + "service");
-
- /*Discover the declared metrics*/
- MetricDeclarations md = this.getClass().getAnnotation(MetricDeclarations.class);
-
- if (md != null && md.metrics().length > 0) {
- for (MetricDecl metric : md.metrics()) {
- log.debug("Found metric: " + metric.mnemonic() + " with "
- + metric.activators().length + " activators");
-
- if (metrics.containsKey(metric.mnemonic())) {
- log.error("Duplicate metric mnemonic " + metric.mnemonic());
- continue;
- }
-
- Metric m = new Metric();
- m.setDescription(metric.descr());
- m.setMnemonic(metric.mnemonic());
- m.setMetricType(new MetricType(MetricType.fromActivator(metric.activators()[0])));
-
- List> activs = new ArrayList>();
- for (Class extends DAObject> o : metric.activators()) {
- activs.add(o);
- }
-
- metricActType.put(m, activs);
-
- activators.addAll(Arrays.asList(metric.activators()));
-
- metrics.put(m.getMnemonic(), m);
- if (metric.dependencies().length > 0)
- dependencies.addAll(Arrays.asList(metric.dependencies()));
- }
- } else {
- log.warn("Plug-in " + getName() + " declares no metrics");
- }
- }
-
- /**
- * Retrieve author information from the plug-in bundle
- */
- public String getAuthor() {
-
- return (String) bc.getBundle().getHeaders().get(
- org.osgi.framework.Constants.BUNDLE_CONTACTADDRESS);
- }
-
- /**
- * Retrieve the plug-in description from the plug-in bundle
- */
- public String getDescription() {
-
- return (String) bc.getBundle().getHeaders().get(
- org.osgi.framework.Constants.BUNDLE_DESCRIPTION);
- }
-
- /**
- * Retrieve the plug-in name as specified in the metric bundle
- */
- public String getName() {
-
- return (String) bc.getBundle().getHeaders().get(
- org.osgi.framework.Constants.BUNDLE_NAME);
- }
-
- /**
- * Retrieve the plug-in version as specified in the metric bundle
- */
- public String getVersion() {
-
- return (String) bc.getBundle().getHeaders().get(
- org.osgi.framework.Constants.BUNDLE_VERSION);
- }
-
- /**
- * Retrieve the installation date for this plug-in version
- */
- public final Date getDateInstalled() {
- return Plugin.getPluginByHashcode(getUniqueKey()).getInstalldate();
- }
-
- Map> blockerObjects = new ConcurrentHashMap>();
-
- /**
- * Call the appropriate getResult() method according to
- * the type of the entity that is measured.
- *
- * Use this method if you don't want the metric results
- * to be calculated on-demand. Otherwise, use getResult().
- *
- * @param o DAO that specifies the desired result type.
- * The type of o is used to dispatch to the correct
- * specialized getResult() method of the sub-interfaces.
- * @return result (measurement) performed by this metric
- * on the project data specified by o.
- * @throws MetricMismatchException if the DAO is of a type
- * not supported by this metric.
- */
- @SuppressWarnings("unchecked")
- public List getResultIfAlreadyCalculated(DAObject o, List l) throws MetricMismatchException {
- boolean found = false;
- List result = new ArrayList();
-
- for (Metric m : l) {
- if (!metrics.containsKey(m.getMnemonic())) {
- throw new MetricMismatchException("Metric " + m.getMnemonic()
- + " not defined by plugin "
- + Plugin.getPluginByHashcode(getUniqueKey()).getName());
- }
- List re = null;
- try {
- Method method = findGetResultMethod(o.getClass());
- re = (List) method.invoke(this, o, m);
- } catch (SecurityException e) {
- logErr("getResult", o, e);
- } catch (NoSuchMethodException e) {
- log.error("No method getResult(" + m.getMetricType().toActivator() + ") for type "
- + this.getClass().getName());
- } catch (IllegalArgumentException e) {
- logErr("getResult", o, e);
- } catch (IllegalAccessException e) {
- logErr("getResult", o, e);
- } catch (InvocationTargetException e) {
- logErr("getResult", o, e);
- }
- if (re != null && !re.isEmpty()) {
- result.addAll(re);
- }
- }
-
- return result;
- }
-
- private Method findGetResultMethod(Class> clazz)
- throws NoSuchMethodException {
- Method m = null;
-
- try {
- m = this.getClass().getMethod("getResult", clazz, Metric.class);
- } catch (NoSuchMethodException nsme) {
- try {
- m = this.getClass().getMethod("getResult", clazz.getSuperclass(), Metric.class);
- } catch (NoSuchMethodException nsme1) {
- throw nsme;
- }
- }
-
- return m;
- }
-
- /**
- * Call the appropriate getResult() method according to
- * the type of the entity that is measured.
- *
- * If the appropriate getResult() doesn't return any value,
- * the metric is forced to calculate the result. Then the
- * appropriate getResult() method is called again.
- *
- * @param o DAO that specifies the desired result type.
- * The type of o is used to dispatch to the correct
- * specialized getResult() method of the sub-interfaces.
- * @return result (measurement) performed by this metric
- * on the project data specified by o.
- * @throws MetricMismatchException if the DAO is of a type
- * not supported by this metric.
- * @throws AlreadyProcessingException
- */
- public List getResult(DAObject o, List l)
- throws MetricMismatchException, AlreadyProcessingException, Exception {
- List r = getResultIfAlreadyCalculated(o, l);
-
- // the result hasn't been calculated yet. Do so.
- if (r == null || r.size() == 0) {
- /*
- * To ensure that no two instances of the metric operate on the same
- * DAO lock on the DAO. Working on the same DAO can happen often
- * when a plugin starts the calculation of another metric as a
- * result of a plugin dependency association. This lock has the side
- * effect that no two Plugins can be invoked with the same DAO as an
- * argument even if the plug-ins do not depend on each other.
- */
- synchronized (lockObject(o)) {
- try {
- run(o);
-
- r = getResultIfAlreadyCalculated(o, l);
- if (r == null || r.size() == 0) {
- if (job.get().state() != Job.State.Yielded)
- log.debug("Metric " + getClass() + " didn't return"
- + "a result even after running it. DAO: "
- + o.getId());
- }
- } finally {
- unlockObject(o);
- }
- }
- }
-
- return r;
- }
-
- private Map> locks = new HashMap>();
-
- private Object lockObject(DAObject o) throws AlreadyProcessingException {
- synchronized (locks) {
- if (!locks.containsKey(o.getId())) {
- locks.put(o.getId(),
- new Pair