diff --git a/.gitignore b/.gitignore index 50b2ed416..8edfabeeb 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,9 @@ bin/ *.ipr *.iws *.db +*.aux +assignment1 report/software reengineering assignment 1 adam kucera maarten duijn.log +assignment1 report/software reengineering assignment 1 adam kucera maarten duijn.pdf +assignment1 report/software reengineering assignment 1 adam kucera maarten duijn.synctex.gz +nb-configuration.xml +alitheia/cache/tmp/* diff --git a/Reverse Engineering and Detection Report.pdf b/Reverse Engineering and Detection Report.pdf new file mode 100644 index 000000000..35b4f0558 Binary files /dev/null and b/Reverse Engineering and Detection Report.pdf differ diff --git a/alitheia/core/alitheia.log b/alitheia/core/alitheia.log new file mode 100644 index 000000000..e69de29bb diff --git a/alitheia/core/hibernate.log b/alitheia/core/hibernate.log new file mode 100644 index 000000000..e69de29bb diff --git a/alitheia/core/perf.log b/alitheia/core/perf.log new file mode 100644 index 000000000..e69de29bb diff --git a/alitheia/core/pom.xml b/alitheia/core/pom.xml index 4203d2dda..07eebd79b 100644 --- a/alitheia/core/pom.xml +++ b/alitheia/core/pom.xml @@ -65,7 +65,7 @@ - + org.osgi diff --git a/alitheia/core/rest.log b/alitheia/core/rest.log new file mode 100644 index 000000000..e69de29bb diff --git a/alitheia/core/src/main/java/class_cyclic_dependency.png b/alitheia/core/src/main/java/class_cyclic_dependency.png new file mode 100644 index 000000000..ef26542f4 Binary files /dev/null and b/alitheia/core/src/main/java/class_cyclic_dependency.png differ diff --git a/alitheia/core/src/main/java/class_cyclic_dependency.ucls b/alitheia/core/src/main/java/class_cyclic_dependency.ucls new file mode 100644 index 000000000..edca72778 --- /dev/null +++ b/alitheia/core/src/main/java/class_cyclic_dependency.ucls @@ -0,0 +1,277 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/alitheia/core/src/main/java/eu/sqooss/core/AlitheiaCore.ucls b/alitheia/core/src/main/java/eu/sqooss/core/AlitheiaCore.ucls new file mode 100644 index 000000000..4cf7afbf4 --- /dev/null +++ b/alitheia/core/src/main/java/eu/sqooss/core/AlitheiaCore.ucls @@ -0,0 +1,388 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file 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..0d3b48a9d 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 @@ -397,7 +397,6 @@ public List doSQL(String sql, Map params) return Collections.emptyList(); } } - public int callProcedure(String procName, List args, Map params) throws SQLException, QueryException { boolean autoSession = !isDBSessionActive(); diff --git a/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/AbstractView.java b/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/AbstractView.java index f79c95031..682d963dd 100644 --- a/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/AbstractView.java +++ b/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/AbstractView.java @@ -33,7 +33,7 @@ package eu.sqooss.impl.service.webadmin; -import java.net.URI; +import java.util.Date; import java.util.Enumeration; import java.util.Locale; import java.util.MissingResourceException; @@ -71,7 +71,8 @@ public abstract class AbstractView { protected static MetricActivator compMA = null; protected static PluginAdmin sobjPA = null; protected static Scheduler sobjSched = null; - protected static TDSService sobjTDS = null; + + protected static TDSService sobjTDS = null; protected static UpdaterService sobjUpdater = null; protected static ClusterNodeService sobjClusterNode = null; protected static SecurityManager sobjSecurity = null; @@ -95,6 +96,12 @@ public abstract class AbstractView { // Some constants that are used internally private static String NULL_PARAM_NAME = "Undefined parameter name!"; + + /** + * Represents the system time at which the WebAdminRender (and thus the + * system) was started. This is required for the system uptime display. + */ + private static long startTime = new Date().getTime(); /** * Instantiates a new AbstractView object. @@ -104,7 +111,7 @@ public abstract class AbstractView { */ public AbstractView(BundleContext bundlecontext, VelocityContext vc) { // Keep the Velocity context instance - this.vc = vc; + AbstractView.vc = vc; this.bc = bundlecontext; sobjCore = AlitheiaCore.getInstance(); @@ -161,6 +168,9 @@ public AbstractView(BundleContext bundlecontext, VelocityContext vc) { sobjLogger.debug("Could not get the security manager's instance."); } } + + + abstract public void exec(HttpServletRequest req); /** * Initializes the various resource bundle with the specified locale. @@ -173,6 +183,27 @@ public static void initResources (Locale locale) { resMsg = getMessagesBundle(locale); } + /** + * Returns a string representing the uptime of the Alitheia core in + * dd:hh:mm:ss format + */ + public static String getUptime() { + long remainder; + long currentTime = new Date().getTime(); + long timeRunning = currentTime - startTime; + + // Get the elapsed time in days, hours, mins, secs + int days = new Long(timeRunning / 86400000).intValue(); + remainder = timeRunning % 86400000; + int hours = new Long(remainder / 3600000).intValue(); + remainder = remainder % 3600000; + int mins = new Long(remainder / 60000).intValue(); + remainder = remainder % 60000; + int secs = new Long(remainder / 1000).intValue(); + + return String.format("%d:%02d:%02d:%02d", days, hours, mins, secs); + } + /** * Retrieves the value of the given resource property from the * resource bundle that stores all label strings. @@ -288,137 +319,6 @@ protected static String debugRequest (HttpServletRequest request) { return b.toString(); } - /** - * Generates a string that contains a 2*num spaces. - *
- * Used for indentation of the HTML content that is generated by the - * various views. - * - * @param num the indentation depth - * - * @return The indentation string. - */ - protected static String sp (long num) { - StringBuilder b = new StringBuilder(); - for (long i = 0; i < num; i++) - b.append(" "); - return b.toString(); - } - - /** - * Generates a simple table row (with two columns) that represents - * a single text input element with a title line. The title line will be - * stored in the first cell, while the text input will be placed in the - * second cell. - *
- * This method is used by the various views for generating simple input - * screens. - * - * @param title the title that will preceed the input element - * @param parName the input element's name - * @param parValue the input element's initial value - * @param in the indentation depth - * - * @return The string that contains the table's row, or an empty string - * upon invalid (null) name of the input element. - */ - protected static String normalInputRow ( - String title, String parName, String parValue, long in) { - // Stores the assembled HTML content - StringBuilder b = new StringBuilder("\n"); - - // Create the input field's row - if (parName != null) { - b.append(sp(in++) + "\n"); - b.append(sp(in) + "" - + "" + ((title != null) ? title : "") + "" - + "\n"); - b.append(sp(in++) + "\n"); - b.append(sp(in) + "\n"); - b.append(sp(--in) + "\n"); - b.append(sp(--in) + "\n"); - } - - // Return the generated content - return b.toString(); - } - - /** - * Generates a simple table row (with two columns) that represents - * a single text message with a title line. The title line will be - * stored in the first cell, while the message will be placed in the - * second cell. - *
- * This method is used by the various views for generating simple info - * screens. - * - * @param title the title that will preceed the text message - * @param value the text message - * @param in the indentation depth - * - * @return The string that contains the table's row. - */ - protected static String normalInfoRow ( - String title, String value, long in) { - // Stores the assembled HTML content - StringBuilder b = new StringBuilder("\n"); - - // Create the info row - b.append(sp(in++) + "\n"); - b.append(sp(in) + "" - + "" + ((title != null) ? title : "") + "" - + "\n"); - b.append(sp(in++) + "\n"); - b.append(sp(in) + ((value != null) ? value : "") + "\n"); - b.append(sp(--in) + "\n"); - b.append(sp(--in) + "\n"); - - // Return the generated content - return b.toString(); - } - - /** - * Produces an HTML fieldset tag which encapsulates the HTML - * content that is stored in the given StringBuilder object. - * - * @param name the fieldset legend's name - * @param css the CSS class name to use - * @param content the HTML content - * @param in the indentation depth - * - * @return The HTML presentation. - */ - protected static String normalFieldset ( - String name, - String css, - StringBuilder content, - long in) { - if ((content != null) && (content.toString().length() > 0)) { - return (sp(in) + "\n" - + sp(++in) + "" - + ((name != null) ? name : "NONAME") - + "\n" - + content.toString() - + sp(--in) + "\n"); - } - return (""); - } - - // TODO: Remove this method, since it is not I18n compatible. - protected static String errorFieldset (StringBuilder errors, long in) { - return normalFieldset("Errors", null, errors, in); - } - /** * Creates a Long object from the content of the given * String object, while handling internally any thrown diff --git a/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/AdminServlet.java b/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/AdminServlet.java index bde9ad0e3..5c7bc11f8 100644 --- a/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/AdminServlet.java +++ b/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/AdminServlet.java @@ -33,21 +33,10 @@ package eu.sqooss.impl.service.webadmin; -import eu.sqooss.core.AlitheiaCore; -import eu.sqooss.impl.service.webadmin.WebAdminRenderer; -import eu.sqooss.service.admin.AdminAction; -import eu.sqooss.service.admin.AdminService; -import eu.sqooss.service.admin.actions.AddProject; -import eu.sqooss.service.db.DBService; -import eu.sqooss.service.logging.Logger; -import eu.sqooss.service.util.Pair; -import eu.sqooss.service.webadmin.WebadminService; - -import java.io.InputStream; import java.io.IOException; +import java.io.InputStream; import java.io.PrintWriter; import java.io.StringWriter; - import java.util.Hashtable; import java.util.Locale; @@ -57,18 +46,19 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.apache.velocity.app.VelocityEngine; import org.apache.velocity.Template; import org.apache.velocity.VelocityContext; - +import org.apache.velocity.app.VelocityEngine; import org.osgi.framework.BundleContext; -import org.osgi.framework.BundleException; -import org.osgi.framework.ServiceReference; + +import eu.sqooss.core.AlitheiaCore; +import eu.sqooss.service.db.DBService; +import eu.sqooss.service.logging.Logger; +import eu.sqooss.service.util.Pair; +import eu.sqooss.service.webadmin.WebadminService; public class AdminServlet extends HttpServlet { private static final long serialVersionUID = 1L; - private static BundleContext bc = null; - private static WebadminService webadmin = null; /// Logger given by our owner to write log messages to. private Logger logger = null; @@ -76,30 +66,17 @@ public class AdminServlet extends HttpServlet { private DBService db = null; // Content tables - private Hashtable dynamicContentMap = null; + private Hashtable> dynamicContentMap = null; private Hashtable> staticContentMap = null; // Dynamic substitutions VelocityContext vc = null; VelocityEngine ve = null; - - // Renderer of content - WebAdminRenderer adminView = null; - - // Plug-ins view - PluginsView pluginsView = null; - - // Projects view - ProjectsView projectsView = null; - - TranslationProxy tr = new TranslationProxy(); public AdminServlet(BundleContext bc, WebadminService webadmin, Logger logger, VelocityEngine ve) { - AdminServlet.webadmin = webadmin; - AdminServlet.bc = bc; this.ve = ve; this.logger = logger; @@ -125,25 +102,45 @@ public AdminServlet(BundleContext bc, addStaticContent("/rules.png", "image/x-png"); // Create the dynamic content map - dynamicContentMap = new Hashtable(); - dynamicContentMap.put("/", "index.html"); - dynamicContentMap.put("/index", "index.html"); - dynamicContentMap.put("/projects", "projects.html"); - dynamicContentMap.put("/projectlist", "projectslist.html"); - dynamicContentMap.put("/logs", "logs.html"); - dynamicContentMap.put("/jobs", "jobs.html"); - dynamicContentMap.put("/alljobs", "alljobs.html"); - dynamicContentMap.put("/users", "users.html"); - dynamicContentMap.put("/rules", "rules.html"); - dynamicContentMap.put("/jobstat", "jobstat.html"); - + dynamicContentMap = new Hashtable>(); + Pair pluginsPair = new Pair("index.html", new PluginsView(bc, vc)); + ProjectsView projectsView = new ProjectsView(bc, vc); + Pair projectsPair = new Pair("projects.html", projectsView); + Pair projectsListPair = new Pair("projectslist.html", projectsView); + Pair logsPair = new Pair("logs.html", new LogsView(bc, vc)); + JobsView jobsView = new JobsView(bc, vc); + Pair jobsPair = new Pair("jobs.html", jobsView); + Pair allJobsPair = new Pair("jobs_all.html", jobsView); + Pair jobStatPair = new Pair("job_stat.html", jobsView); + Pair rulesPair = new Pair("rules.html", new RulesView(bc, vc)); + Pair resultsPair = new Pair("results.html", new ResultsView(bc, vc)); + + dynamicContentMap.put("/", pluginsPair); + dynamicContentMap.put("/index", pluginsPair); + dynamicContentMap.put("/projects", projectsPair); + dynamicContentMap.put("/projectlist", projectsListPair); + dynamicContentMap.put("/logs", logsPair); + dynamicContentMap.put("/jobs", jobsPair); + dynamicContentMap.put("/alljobs", allJobsPair); + dynamicContentMap.put("/jobstat", jobStatPair); + dynamicContentMap.put("/rules", rulesPair); + dynamicContentMap.put("/start", resultsPair); + dynamicContentMap.put("/stop", resultsPair); + dynamicContentMap.put("/restart", resultsPair); + dynamicContentMap.put("/addproject", resultsPair); + dynamicContentMap.put("/diraddproject", resultsPair); + // Now the dynamic substitutions and renderer vc = new VelocityContext(); - adminView = new WebAdminRenderer(bc, vc); - - // Create the various view objects - pluginsView = new PluginsView(bc, vc); - projectsView = new ProjectsView(bc, vc); + + // Object-based substitutions + vc.put("tr", new TranslationProxy()); + vc.put("metrics", pluginsPair.second); + vc.put("projects", projectsPair.second); + vc.put("logs", logsPair.second); + vc.put("jobs", jobsPair.second); + vc.put("rules", rulesPair.second); + vc.put("results", resultsPair.second); } /** @@ -154,86 +151,60 @@ private void addStaticContent(String path, String type) { staticContentMap.put(path, p); } + /** + * Handles http GET requests, delegates most of its functionality to handleRequest + */ + @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - if (!db.isDBSessionActive()) { - db.startDBSession(); - } - - try { - String query = request.getPathInfo(); - - // Add the request to the log - logger.debug("GET:" + query); - - // This is static content - if (query.startsWith("/stop")) { - vc.put("RESULTS", "

Alitheia Core is now shutdown.

"); - sendPage(response, request, "/results.html"); - - // Now stop the system - logger.info("System stopped by user request to webadmin."); - try { - bc.getBundle(0).stop(); - } catch (BundleException be) { - logger.warn("Could not stop bundle 0."); - // And ignore - } - return; - } - if (query.startsWith("/restart")) { - vc.put("RESULTS", "

Alitheia Core is now restarting.

"); - sendPage(response, request, "/results.html"); - - //FIXME: How do we do a restart? - return; - } - else if ((query != null) && (staticContentMap.containsKey(query))) { - sendResource(response, staticContentMap.get(query)); - } - else if ((query != null) && (dynamicContentMap.containsKey(query))) { - sendPage(response, request, dynamicContentMap.get(query)); - } - } catch (NullPointerException e) { - logger.warn("Got a NPE while rendering a page.",e); - response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); - } finally { - if (db.isDBSessionActive()) { - db.commitDBSession(); - } - } + if(request != null && request.getPathInfo() != null) { + logger.debug("POST:" + request.getPathInfo()); + handleRequest(request, response); + } } + /** + * Handles http POST requests, delegates most of its functionality to handleRequest + */ + @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - if (!db.isDBSessionActive()) { + if(request != null && request.getPathInfo() != null) { + logger.debug("POST:" + request.getPathInfo()); + handleRequest(request, response); + } + } + + /** + * Method that receives incoming requests and delegates further handling to the View classes + * + * @param request the received request + * @param response the response that will be sent back + * @throws ServletException + * @throws IOException + */ + private void handleRequest(HttpServletRequest request, + HttpServletResponse response) throws ServletException, + IOException { + if (!db.isDBSessionActive()) { db.startDBSession(); } try { String query = request.getPathInfo(); - logger.debug("POST:" + query); - - if (query.startsWith("/addproject")) { - //addProject(request); - sendPage(response, request, "/results.html"); - } else if (query.startsWith("/diraddproject")) { - AdminService as = AlitheiaCore.getInstance().getAdminService(); - AdminAction aa = as.create(AddProject.MNEMONIC); - aa.addArg("dir", request.getParameter("properties")); - as.execute(aa); - if (aa.hasErrors()) - vc.put("RESULTS", aa.errors()); - else - vc.put("RESULTS", aa.results()); - sendPage(response, request, "/results.html"); - } else { - doGet(request,response); + if (staticContentMap.containsKey(query)) { + sendResource(response, staticContentMap.get(query)); + } + else if (dynamicContentMap.containsKey(query)) { + //Handle appropriate request + dynamicContentMap.get(query).second.exec(request); + //Serve content + sendPage(response, request, dynamicContentMap.get(query).first); } } catch (NullPointerException e) { - logger.warn("Got a NPE while handling POST data."); + logger.warn("Got a NPE while handling request data."); response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); } finally { if (db.isDBSessionActive()) { @@ -263,13 +234,11 @@ protected void sendResource(HttpServletResponse response, Pair so byte[] buffer = new byte[1024]; int bytesRead = 0; - int totalBytes = 0; response.setContentType(source.second); ServletOutputStream ostream = response.getOutputStream(); while ((bytesRead = istream.read(buffer)) > 0) { - ostream.write(buffer,0,bytesRead); - totalBytes += bytesRead; + ostream.write(buffer, 0, bytesRead); } } @@ -309,15 +278,8 @@ private void createSubstitutions(HttpServletRequest request) { + " SQO-OSS Consortium Members" + ""); vc.put("LOGO", ""); - vc.put("UPTIME", WebAdminRenderer.getUptime()); - - // Object-based substitutions - vc.put("scheduler", adminView.sobjSched.getSchedulerStats()); - vc.put("tr",tr); // translations proxy - vc.put("admin",adminView); - vc.put("projects",projectsView); - vc.put("metrics",pluginsView); - vc.put("request", request); // The request can be used by the render() methods + + vc.put("request", request); } /** diff --git a/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/JobsView.java b/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/JobsView.java new file mode 100644 index 000000000..3fdb67b59 --- /dev/null +++ b/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/JobsView.java @@ -0,0 +1,69 @@ +package eu.sqooss.impl.service.webadmin; + +import java.util.HashMap; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.velocity.VelocityContext; +import org.osgi.framework.BundleContext; + +import eu.sqooss.service.scheduler.Job; +import eu.sqooss.service.scheduler.SchedulerStats; + +public class JobsView extends AbstractView { + + public JobsView(BundleContext bundlecontext, VelocityContext vc) { + super(bundlecontext, vc); + } + + @Override + public void exec(HttpServletRequest req) { + } + + /** + * Returns the statistics about Failed Jobs. + * + * @return HashMap with Failed Jobs stats + */ + public static HashMap getFailedJobStats() { + return sobjSched.getSchedulerStats().getFailedJobTypes(); + } + + /** + * Returns the array of Failed Jobs + * + * @return Array of Failed Jobs + */ + public static Job[] getFailedJobs() { + return sobjSched.getFailedQueue(); + } + + /** + * Returns the statistics about Waiting Jobs. + * + * @return HashMap with Waiting Jobs stats + */ + public static HashMap getWaitingJobs() { + return sobjSched.getSchedulerStats().getWaitingJobTypes(); + } + + /** + * Returns List of names of running jobs. + * + * @return List of Strings - running jobs names + */ + public static List getRunningJobs() { + return sobjSched.getSchedulerStats().getRunJobs(); + } + + + /** + * Returns the current statistics of the scheduler + * + * @return SchedulerStats with the relevevant scheduler information + */ + public static SchedulerStats getSchedulerStats() { + return sobjSched.getSchedulerStats(); + } +} diff --git a/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/LogsView.java b/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/LogsView.java new file mode 100644 index 000000000..7ad7b49de --- /dev/null +++ b/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/LogsView.java @@ -0,0 +1,39 @@ +package eu.sqooss.impl.service.webadmin; + +import java.util.ArrayList; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.velocity.VelocityContext; +import org.osgi.framework.BundleContext; + +import eu.sqooss.service.util.StringUtils; + +public class LogsView extends AbstractView { + + public LogsView(BundleContext bundlecontext, VelocityContext vc) { + super(bundlecontext, vc); + } + + @Override + public void exec(HttpServletRequest req) { + } + + /** + * Creates an HTML safe list of the logs + * + * @return List with HTML safe log strings + */ + public static List getLogs() { + String[] names = sobjLogManager.getRecentEntries(); + ArrayList logs = new ArrayList(); + if (names != null) { + for (String name : names) { + logs.add(StringUtils.makeXHTMLSafe(name)); + } + } + return logs; + } + +} diff --git a/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/PluginsView.java b/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/PluginsView.java index 9a582edb4..7ad830b9e 100644 --- a/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/PluginsView.java +++ b/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/PluginsView.java @@ -1,4 +1,4 @@ -/* +/*RVALA * 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. * @@ -40,6 +40,7 @@ import javax.servlet.http.HttpServletRequest; import org.apache.velocity.VelocityContext; +import org.hibernate.Hibernate; import org.osgi.framework.BundleContext; import org.osgi.framework.Constants; @@ -51,935 +52,432 @@ import eu.sqooss.service.pa.PluginInfo.ConfigurationType; import eu.sqooss.service.util.StringUtils; -public class PluginsView extends AbstractView{ - - public PluginsView(BundleContext bundlecontext, VelocityContext vc) { - super(bundlecontext, vc); - } - - /** - * Renders the various plug-in's views. - * - * @param req the servlet's request object - * - * @return The HTML presentation of the generated view. - */ - public static String render(HttpServletRequest req) { - // Stores the assembled HTML content - StringBuilder b = new StringBuilder("\n"); - // Stores the accumulated error messages - StringBuilder e = new StringBuilder(); - // Indentation spacer - long in = 6; - - // Request parameters - String reqParAction = "action"; - String reqParHashcode = "pluginHashcode"; - String reqParPropName = "propertyName"; - String reqParPropDescr = "propertyDescription"; - String reqParPropType = "propertyType"; - String reqParPropValue = "propertyValue"; - String reqParShowProp = "showProperties"; - String reqParShowActv = "showActivators"; - // Recognized "action" parameter's values - String actValInstall = "installPlugin"; - String actValUninstall = "uninstallPlugin"; - String actValSync = "syncPlugin"; - String actValReqAddProp = "createProperty"; - String actValReqUpdProp = "updateProperty"; - String actValConAddProp = "confirmProperty"; - String actValConRemProp = "removeProperty"; - // Request values - String reqValAction = ""; - String reqValHashcode = null; - String reqValPropName = null; - String reqValPropDescr = null; - String reqValPropType = null; - String reqValPropValue = null; - boolean reqValShowProp = false; // Show plug-in properties - boolean reqValShowActv = false; // Show plug-in activators - // Info object of the selected plug-in - PluginInfo selPI = null; - - // Proceed only when at least one plug-in is registered - if (sobjPA.listPlugins().isEmpty()) { - b.append(normalFieldset( - "All plug-ins", - null, - new StringBuilder("" - + "No plug-ins found! " - + "" - + ""), - in)); - } - else { - // =============================================================== - // Parse the servlet's request object - // =============================================================== - if (req != null) { - // DEBUG: Dump the servlet's request parameter - if (DEBUG) { - b.append(debugRequest(req)); - } - - // Retrieve the selected editor's action (if any) - reqValAction = req.getParameter(reqParAction); - if (reqValAction == null) { - reqValAction = ""; - }; - // Retrieve the various display flags - if ((req.getParameter(reqParShowProp) != null) - && (req.getParameter(reqParShowProp).equals("true"))) { - reqValShowProp = true; - } - if ((req.getParameter(reqParShowActv) != null) - && (req.getParameter(reqParShowActv).equals("true"))) { - reqValShowActv = true; - } - // Retrieve the selected configuration property's values - if ((reqValAction.equals(actValConAddProp)) - || (reqValAction.equals(actValReqUpdProp)) - || (reqValAction.equals(actValConRemProp))) { - // Name, description, type and value - reqValPropName = req.getParameter(reqParPropName); - reqValPropDescr = req.getParameter(reqParPropDescr); - reqValPropType = req.getParameter(reqParPropType); - reqValPropValue = req.getParameter(reqParPropValue); - } - // Retrieve the selected plug-in's hash code - reqValHashcode = req.getParameter(reqParHashcode); - // Plug-in based actions - if (reqValHashcode != null) { - // ======================================================= - // Plug-in install request - // ======================================================= - if (reqValAction.equals(actValInstall)) { - if (sobjPA.installPlugin(reqValHashcode) == false) { - e.append("Plug-in can not be installed!" - + " Check log for details."); - } - // Persist the DB changes - else { - PluginInfo pInfo = - sobjPA.getPluginInfo(reqValHashcode); - sobjPA.pluginUpdated(sobjPA.getPlugin(pInfo)); - } - } - // ======================================================= - // Plug-in un-install request - // ======================================================= - else if (reqValAction.equals(actValUninstall)) { - if (sobjPA.uninstallPlugin(reqValHashcode) == false) { - e.append("Plug-in can not be uninstalled." - + " Check log for details."); - } else { - e.append("A job was scheduled to remove the plug-in"); - } - } - } - // Retrieve the selected plug-in's info object - if (reqValHashcode != null) { - selPI = sobjPA.getPluginInfo(reqValHashcode); - } - // Plug-in info based actions - if ((selPI != null) && (selPI.installed)) { - // ======================================================= - // Plug-in synchronize (on all projects) request - // ======================================================= - if (reqValAction.equals(actValSync)) { - compMA.syncMetrics(sobjPA.getPlugin(selPI)); - } - // ======================================================= - // Plug-in's configuration property removal - // ======================================================= - else if (reqValAction.equals(actValConRemProp)) { - if (selPI.hasConfProp( - reqValPropName, reqValPropType)) { - try { - if (selPI.removeConfigEntry( - sobjDB, - reqValPropName, - reqValPropType)) { - // Update the Plug-in Admin's information - sobjPA.pluginUpdated( - sobjPA.getPlugin(selPI)); - // Reload the PluginInfo object - selPI = sobjPA.getPluginInfo( - reqValHashcode); - } - else { - e.append("Property removal" - + " has failed!" - + " Check log for details."); - } - } - catch (Exception ex) { - e.append(ex.getMessage()); - } - } - else { - e.append ("Unknown configuration property!"); - } - // Return to the update view upon error - if (e.toString().length() > 0) { - reqValAction = actValReqUpdProp; - } - } - // ======================================================= - // Plug-in's configuration property creation/update - // ======================================================= - else if (reqValAction.equals(actValConAddProp)) { - // Check for a property update - boolean update = selPI.hasConfProp( - reqValPropName, reqValPropType); - // Update configuration property - if (update) { - try { - if (selPI.updateConfigEntry( - sobjDB, - reqValPropName, - reqValPropValue)) { - // Update the Plug-in Admin's information - sobjPA.pluginUpdated( - sobjPA.getPlugin(selPI)); - // Reload the PluginInfo object - selPI = - sobjPA.getPluginInfo(reqValHashcode); - } - else { - e.append("Property update" - + " has failed!" - + " Check log for details."); - } - } - catch (Exception ex) { - e.append(ex.getMessage()); - } - } - // Create configuration property - else { - try { - if (selPI.addConfigEntry( - sobjDB, - reqValPropName, - reqValPropDescr, - reqValPropType, - reqValPropValue)) { - // Update the Plug-in Admin's information - sobjPA.pluginUpdated( - sobjPA.getPlugin(selPI)); - // Reload the PluginInfo object - selPI = - sobjPA.getPluginInfo(reqValHashcode); - } - else { - e.append("Property creation" - + " has failed!" - + " Check log for details."); - } - } - catch (Exception ex) { - e.append(ex.getMessage()); - } - } - // Return to the create/update view upon error - if (e.toString().length() > 0) { - if (update) reqValAction = actValReqUpdProp; - else reqValAction = actValReqAddProp; - } - } - } - } - - // =============================================================== - // Create the form - // =============================================================== - b.append(sp(in++) + "
\n"); - - // =============================================================== - // Display the accumulated error messages (if any) - // =============================================================== - b.append(errorFieldset(e, in)); - - // =============================================================== - // "Create/update configuration property" editor - // =============================================================== - if ((selPI != null) && (selPI.installed) - && ((reqValAction.equals(actValReqAddProp)) - || (reqValAction.equals(actValReqUpdProp)))) { - // Input field values are stored here - String value = null; - // Create the field-set - b.append(sp(in) + "
\n"); - // Check for a property update request - boolean update = selPI.hasConfProp( - reqValPropName, reqValPropType); - b.append(sp(++in) + "" - + ((update) - ? "Update property of " - : "Create property for ") - + selPI.getPluginName() - + "\n"); - b.append(sp(in) + ""); - // Property's name - value = ((reqValPropName != null) ? reqValPropName : ""); - b.append(sp(in) + "\n" - + sp(++in) - + "\n" - + sp(in) - + "\n" - + sp(--in) + "\n"); - // Property's description - value = ((reqValPropDescr != null) ? reqValPropDescr : ""); - b.append(sp(in) + "\n" - + sp(++in) - + "\n" - + sp(in) - + "\n" - + sp(--in) + "\n"); - // Property's type - value = ((reqValPropType != null) ? reqValPropType : ""); - b.append(sp(in) + "\n" - + sp(++in) - + "\n" - + sp(in) - + "\n" - + sp(--in) - + "\n"); - // Property's value - value = ((reqValPropValue != null) ? reqValPropValue : ""); - b.append(sp(in) + "\n" - + sp(++in) - + "\n" - + sp(in) - + "\n" - + sp(--in) - + "\n"); - // Command tool-bar - value = ((update) ? "Update" : "Create"); - b.append(sp(in) + "\n" - + sp(++in) - + "\n" - + sp(--in) - + "\n"); - b.append(sp(--in) + "
" - + "Name" - + "" - + ((update) ? value - : "") - + "
" - + "Description" - + "" - + ((update) ? value - : "") - + "
" - + "Type" - + "\n" - + sp(++in)); - if (update) { - b.append(value); - } - else { - b.append("\n"); - } - b.append(sp(--in) - + "
" - + "Value" - + "" - + "" - + "
" - + "" - + " "); - if (update) { - b.append(sp(in) + "" - + " "); - } - b.append(sp(in) + "" - + "
"); - b.append(sp(--in) + "
\n"); - } - // =============================================================== - // Plug-in editor - // =============================================================== - else if (selPI != null) { - // Create the plug-in field-set - b.append(sp(in) + "
\n"); - b.append(sp(++in) + "" - + selPI.getPluginName() - + "\n"); - //------------------------------------------------------------ - // Create the plug-in info table - //------------------------------------------------------------ - b.append(sp(in) + "\n"); - b.append(sp(++in) + "\n"); - b.append(sp(++in) + "\n"); - b.append(sp(++in) + "\n"); - b.append(sp(in) + "\n"); - b.append(sp(in) + "\n"); - b.append(sp(in) + "\n"); - b.append(sp(--in) + "\n"); - b.append(sp(--in) + "\n"); - // Display the plug-in's info - b.append(sp(in) + "\n"); - b.append(sp(in++) + "\n"); - // Plug-in state - b.append(sp(++in) + "\n"); - // Plug-in name - b.append(sp(in) + "\n"); - // Plug-in class - b.append(sp(in) + "\n"); - // Plug-in version - b.append(sp(in) + "\n"); - b.append(sp(--in) + "\n"); - // Plug-in tool-bar - b.append(sp(in++) + "\n"); - b.append(sp(in++) + "\n"); - b.append(sp(--in) + "\n"); - // Close the plug-in table - b.append(sp(--in) + "\n"); - b.append(sp(--in) + "
" - + "Status" - + "Name" - + "ClassVersion
" - + ((selPI.installed) - ? "Installed" : "Registered") - + "" - + selPI.getPluginName() + "" - + StringUtils.join((String[]) ( - selPI.getServiceRef().getProperty( - Constants.OBJECTCLASS)),",") - + "" - + selPI.getPluginVersion() + "
\n"); - b.append(sp(in) + "\n"); - if (selPI.installed) { - b.append(sp(in) + "\n"); - b.append(sp(in) + "\n"); - } - else { - b.append(sp(in) + "\n"); - } - b.append(sp(--in) + "
\n"); - - //------------------------------------------------------------ - // Registered metrics, activators and configuration - //------------------------------------------------------------ - if (selPI.installed) { - //-------------------------------------------------------- - // Create the metrics field-set - //-------------------------------------------------------- - b.append(sp(++in) + "
\n"); - b.append(sp(++in) + "" - + "Supported metrics" - + "\n"); - // Create the metrics table - b.append(sp(in) + "\n"); - b.append(sp(++in) + "\n"); - b.append(sp(++in) + "\n"); - b.append(sp(++in) + "\n"); - b.append(sp(in) + "\n"); - b.append(sp(in) + "\n"); - b.append(sp(in) + "\n"); - b.append(sp(--in) + "\n"); - b.append(sp(--in) + "\n"); - // Display the list of supported metrics - b.append(sp(in++) + "\n"); - // Get the list of supported metrics - List metrics = - sobjPA.getPlugin(selPI).getAllSupportedMetrics(); - if ((metrics == null) || (metrics.isEmpty())) { - b.append(sp(in++) + ""); - b.append(sp(in) + "\n"); - b.append(sp(--in)+ "\n"); - } - else { - for (Metric metric: metrics) { - b.append(sp(in++) + "\n"); - b.append(sp(in) + "\n"); - b.append(sp(in) + "\n"); - b.append(sp(in) + "\n"); - b.append(sp(in) + "\n"); - b.append(sp(--in)+ "\n"); - } - } - // Close the metrics table - b.append(sp(--in) + "\n"); - // Close the metrics table - b.append(sp(--in) + "
" - + "Id" - + "Name" - + "Type" - + "Description
" - + "This plug-in does not support metrics." - + "
" - + metric.getId() + "" - + metric.getMnemonic() + "" - + metric.getMetricType().getType() - + "" - + metric.getDescription() + "
\n"); - // Close the metric field-set - b.append(sp(--in) + "
\n"); - //-------------------------------------------------------- - // Create the properties field-set - //-------------------------------------------------------- - b.append(sp(++in) + "
\n"); - b.append(sp(++in) + "" - + "Configuration properties" - + "\n"); - // Create the properties table - b.append(sp(in) + "\n"); - b.append(sp(++in) + "\n"); - b.append(sp(++in) + "\n"); - b.append(sp(++in) + "\n"); - b.append(sp(in) + "\n"); - b.append(sp(in) + "\n"); - b.append(sp(--in) + "\n"); - b.append(sp(--in) + "\n"); - // Display the set of configuration properties - b.append(sp(in++) + "\n"); - // Get the plug-in's configuration set - Set config = Plugin.getPluginByHashcode(selPI.getHashcode()).getConfigurations(); - if ((config == null) || (config.isEmpty())) { - b.append(sp(in++) + ""); - b.append(sp(in) + "\n"); - b.append(sp(--in)+ "\n"); - } - else { - for (PluginConfiguration param : config) { - b.append(sp(in++) + "\n"); - // Property's name and description - String description = param.getMsg(); - if (param.getMsg() == null) - description = "No description available."; - b.append(sp(in) + "\n"); - // Property's type - b.append(sp(in) + "\n"); - // Property's value - b.append(sp(in) + "\n"); - b.append(sp(--in)+ "\n"); - } - } - // Command tool-bar - b.append(sp(in) + "\n"); - b.append(sp(++in) + "\n"); - b.append(sp(--in) + "\n"); - // Close the properties table - b.append(sp(--in) + "\n"); - // Close the properties table - b.append(sp(--in) + "
" - + "Name" - + "Type" - + "Value
" - + "This plug-in has no configuration properties." - + "
" - + "\"[Edit]\"/" - + " " + param.getName() - + "" - + param.getType() - + "" - + param.getValue() - + "
\n"); - b.append(sp(++in) + "\n"); - b.append(sp(--in) + "
\n"); - // Close the properties field-set - b.append(sp(--in) + "
\n"); - } - - // Close the plug-in field-set - b.append(sp(--in) + "
\n"); - } - // =============================================================== - // Plug-ins list - // =============================================================== - else { - // Create the field-set - b.append(sp(in) + "
\n"); - b.append(sp(++in) + "All plug-ins\n"); - // Retrieve information for all registered metric plug-ins - Collection l = sobjPA.listPlugins(); - //------------------------------------------------------------ - // Create the header row - //------------------------------------------------------------ - b.append(sp(in) + "\n"); - b.append(sp(++in) + "\n"); - b.append(sp(++in) + "\n"); - b.append(sp(++in) + "\n"); - b.append(sp(in) + "\n"); - b.append(sp(in) + "\n"); - b.append(sp(in) + "\n"); - b.append(sp(--in) + "\n"); - b.append(sp(--in) + "\n"); - //------------------------------------------------------------ - // Create the content row - //------------------------------------------------------------ - b.append(sp(in++) + "\n"); - //------------------------------------------------------------ - // Display not-installed plug-ins first - //------------------------------------------------------------ - for(PluginInfo i : l) { - if (i.installed == false) { - b.append(sp(in) + "\n"); - // Plug-in state - b.append(sp(++in) + "\n"); - // Plug-in name - b.append(sp(in) + "\n"); - // Plug-in class - b.append(sp(in) + "\n"); - // Plug-in version - b.append(sp(in) + "\n"); - b.append(sp(--in) + "\n"); - // Extended plug-in information - b.append(renderPluginAttributes( - i, reqValShowProp, reqValShowActv, in)); - } - } - //------------------------------------------------------------ - // Installed plug-ins - //------------------------------------------------------------ - for(PluginInfo i : l) { - if (i.installed) { - b.append(sp(in) + "\n"); - // Plug-in state - b.append(sp(++in) + "\n"); - // Plug-in name - b.append(sp(in) + "\n"); - // Plug-in class - b.append(sp(in) + "\n"); - // Plug-in version - b.append(sp(in) + "\n"); - b.append(sp(--in) + "\n"); - // Extended plug-in information - b.append(renderPluginAttributes( - i, reqValShowProp, reqValShowActv, in)); - } - } - //------------------------------------------------------------ - // Close the table - //------------------------------------------------------------ - b.append(sp(--in) + "\n"); - b.append(sp(--in) + "
" - + "Status" - + "Name" - + "ClassVersion
" - + "\"[Edit]\"/" - + " Registered" - + i.getPluginName() - + "" - + StringUtils.join((String[]) ( - i.getServiceRef().getProperty( - Constants.OBJECTCLASS)),",") - + "" - + i.getPluginVersion() + "
" - + "\"[Edit]\"/" - + " Installed" - + i.getPluginName() - + "" - + StringUtils.join((String[]) ( - i.getServiceRef().getProperty( - Constants.OBJECTCLASS)),",") - + "" - + i.getPluginVersion() + "
\n"); - //------------------------------------------------------------ - // Display flags - //------------------------------------------------------------ - b.append(sp(in) + "\n"); - b.append(sp(++in) + "Display properties\n"); - b.append(sp(++in) + "Display activators\n"); - b.append(sp(--in) + "\n"); - // Close the field-set - b.append(sp(--in) + "
\n"); - } - - // =============================================================== - // INPUT FIELDS - // =============================================================== - // "Action type" input field - b.append(sp(in) + "\n"); - // "Selected plug-in's hash code" input field - b.append(sp(in) + "\n"); - // "Configuration attribute's name" input field - b.append(sp(in) + "\n"); - // "Configuration attribute's description" input field - b.append(sp(in) + "\n"); - // "Configuration attribute's type" input field - b.append(sp(in) + "\n"); - // "Configuration attribute's value" input field - b.append(sp(in) + "\n"); - // "Show configuration properties" input field - b.append(sp(in) + "\n"); - // "Show activators" input field - b.append(sp(in) + "\n"); - - // =============================================================== - // Close the form - // =============================================================== - b.append(sp(--in) + "
\n"); - } - - return b.toString(); - } - - /** - * Creates a set of table rows populated with the plug-in properties and - * activators, as found in the given PluginInfo object - * - * @param pluginInfo the plug-in's PluginInfo object - * @param showProperties display flag - * @param showActivators display flag - * @param in indentation value for the generated HTML content - * - * @return The table as HTML presentation. - */ - private static String renderPluginAttributes( - PluginInfo pluginInfo, - boolean showProperties, - boolean showActivators, - long in) { - // Stores the assembled HTML content - StringBuilder b = new StringBuilder(); - // List the metric plug-in's configuration properties - if (showProperties) { - Set l = - pluginInfo.getConfiguration(); - // Skip if this plug-ins has no configuration - if ((l != null) && (l.isEmpty() == false)) { - for (PluginConfiguration property : l) { - b.append(sp(in++) + ""); - b.append(sp(in) + " \n"); - b.append(sp(in) + "" - + "Property: " + property.getName() - + " Type: " + property.getType() - + " Value: " + property.getValue() - + "\n"); - b.append(sp(--in)+ "\n"); - } - } - } - // List the metric plug-in's activator types - if (showActivators) { - Set> activators = - pluginInfo.getActivationTypes(); - // Skip if this plug-ins has no activators - if (activators != null) { - for (Class activator : activators) { - b.append(""); - b.append(" \n"); - b.append("" - + "Activator: " - + activator.getName() - + ""); - b.append("\n"); - } - } - } - return b.toString(); - } +public class PluginsView extends AbstractView { + + // error messages + private static StringBuilder e; + // Info object of the selected plug-in + private static PluginInfo selPI = null; + // request variables for easier access + private static String reqValPropName = null; + private static String reqValPropDescr = null; + private static String reqValPropType = null; + private static String reqValPropValue = null; + private static String reqValAction = ""; + private static String reqValHashcode = null; + private static boolean reqValShowProp = false; // Show plug-in properties + private static boolean reqValShowActv = false; // Show plug-in activators + + public PluginsView(BundleContext bundlecontext, VelocityContext vc) { + super(bundlecontext, vc); + e = new StringBuilder(); + } + + /** + * Determines whether the list of available plugins is empty. + * + * @return boolean is list of available plugins empty? + */ + public static boolean isPluginsListEmpty() { + return sobjPA.listPlugins().isEmpty(); + } + + /** + * Returns the collection of available plugins. + * + * @return Collection available plugins + */ + public static Collection getPluginsList() { + return sobjPA.listPlugins(); + } + + /** + * Returns the String of error messages collected during request execution. + * + * @return String Error messages. + */ + public static String getErrorMessages() { + if (e.length() > 0) { + return e.toString(); + } else { + return null; + } + } + + /** + * Returns the currently selected plugin. + * + * @return PluginInfo Selected plugin. + */ + public static PluginInfo getSelectedPlugin() { + return selPI; + } + + /** + * Returns the request property name. + * + * @return String Request property name + */ + public static String getValPropName() { + return (reqValPropName != null) ? reqValPropName : ""; + } + + /** + * Returns the request property type. + * + * @return String Request property type + */ + public static String getValPropType() { + return (reqValPropType != null) ? reqValPropType : ""; + } + + /** + * Returns the request property description. + * + * @return String Request property description. + */ + public static String getValPropDescr() { + return (reqValPropDescr != null) ? reqValPropDescr : ""; + } + + /** + * Returns the request property value. + * + * @return String Request property value + */ + public static String getValPropValue() { + return (reqValPropValue != null) ? reqValPropValue : ""; + } + + /** + * Returns request action. + * + * @return String Request action + */ + public static String getValAction() { + return (reqValAction != null) ? reqValAction : ""; + } + + /** + * Returns request hashcode. + * + * @return String Request hashcode + */ + public static String getValHashcode() { + return (reqValHashcode != null) ? reqValHashcode : ""; + } + + /** + * Determines if properties of plugins should be shown. + * + * @return boolean Should properties of plugins be shown? + */ + public static boolean getValShowProp() { + return reqValShowProp; + } + + /** + * Determines if activities of plugins should be shown. + * + * @return boolean Should activities of plugins be shown? + */ + public static boolean getValShowActv() { + return reqValShowActv; + } + + /** + * Returns array of configuration types. + * + * @return ConfigurationType[] Configuration types + */ + public static ConfigurationType[] getConfigurationTypes() { + return ConfigurationType.values(); + } + + /** + * Returns list of metrics of given plugin. + * + * @param pi + * plugin to show metrics of + * @return List list of metrics for given plugin + */ + public static List getPluginMetrics(PluginInfo pi) { + if (pi == null) + return null; + return sobjPA.getPlugin(pi).getAllSupportedMetrics(); + } + + /** + * Determines if the list of plugin metrics is empty. + * + * @param pi + * given plugin + * @return boolean Is list of metrics of given plugin empty? + */ + public static boolean isPluginMetricsEmpty(PluginInfo pi) { + if (pi == null) + return true; + List metrics = sobjPA.getPlugin(pi).getAllSupportedMetrics(); + if ((metrics == null) || (metrics.isEmpty())) { + return true; + } + return false; + } + + /** + * Returns the configuration of given plugin. + * + * @param pi + * given plugin + * @return Set configuration of given plugin + */ + public static Set getPluginConfiguration(PluginInfo pi) { + if (pi == null) + return null; + return Plugin.getPluginByHashcode(pi.getHashcode()).getConfigurations(); + } + + /** + * Determines if the list of configuration of plugin is empty. + * + * @param pi + * given plugin + * @return Is list of configuration of plugin empty? + */ + public static boolean isPluginConfigurationEmpty(PluginInfo pi) { + if (pi == null) + return true; + Set config = Plugin.getPluginByHashcode( + pi.getHashcode()).getConfigurations(); + if ((config == null) || (config.isEmpty())) { + return true; + } else { + return false; + } + } + + /** + * Determines if the DEBUG variable is on. + * @return Is DEBUG on? + */ + public static boolean isDebugOn() { + return DEBUG; + } + + /** + * Retrieves data from the request required for rendering and executes the request. + * @param req + */ + public void exec(HttpServletRequest req) { + // reinitialize all request variables + e = new StringBuilder(); + selPI = null; + reqValPropName = null; + reqValPropDescr = null; + reqValPropType = null; + reqValPropValue = null; + reqValAction = ""; + reqValHashcode = null; + reqValShowProp = false; // Show plug-in properties + reqValShowActv = false; // Show plug-in activators + + // Proceed only when at least one plug-in is registered + if (!isPluginsListEmpty()) { + + retrieveEditorsAction(req); + retrieveDisplayFlags(req); + retrieveSelectedConfigurationPropertyValues(req); + // Retrieve the selected plug-in's hash code + reqValHashcode = req.getParameter(WebAdminConstants.REQ_PAR_HASHCODE); + + // Plug-in based actions + if (reqValHashcode != null) { + processPluginInstallRequests(); + } + + // Retrieve the selected plug-in's info object + if (reqValHashcode != null) { + selPI = sobjPA.getPluginInfo(reqValHashcode); + } + + // Plug-in info based actions + if ((selPI != null) && (selPI.installed)) { + // ======================================================= + // Plug-in synchronize (on all projects) request + // ======================================================= + if (reqValAction.equals(WebAdminConstants.ACT_VAL_SYNC)) { + compMA.syncMetrics(sobjPA.getPlugin(selPI)); + } + // ======================================================= + // Plug-in's configuration property removal + // ======================================================= + else if (reqValAction.equals(WebAdminConstants.ACT_VAL_CON_REM_PROP)) { + removePluginConfigurationProperty(); + } + // ======================================================= + // Plug-in's configuration property creation/update + // ======================================================= + else if (reqValAction.equals(WebAdminConstants.ACT_VAL_CON_ADD_PROP)) { + // Check for a property update + boolean update = selPI.hasConfProp(reqValPropName, + reqValPropType); + // Update configuration property + if (update) { + updatePluginConfigurationProperty(); + } + // Create configuration property + else { + createPluginConfigurationProperty(); + } + // Return to the create/update view upon error + if (e.toString().length() > 0) { + if (update) + reqValAction = WebAdminConstants.ACT_VAL_REQ_UPD_PROP; + else + reqValAction = WebAdminConstants.ACT_VAL_REQ_ADD_PROP; + } + } + } + } + } + + /** + * Retrieve the selected editor's action (if any) + * + * @param req + */ + private static void retrieveEditorsAction(HttpServletRequest req) { + reqValAction = req.getParameter(WebAdminConstants.REQ_PAR_ACTION); + if (reqValAction == null) { + reqValAction = ""; + } + } + + /** + * Retrieve the various display flags + * + * @param req + */ + private static void retrieveDisplayFlags(HttpServletRequest req) { + if ((req.getParameter(WebAdminConstants.REQ_PAR_SHOW_PROP) != null) + && (req.getParameter(WebAdminConstants.REQ_PAR_SHOW_PROP) + .equals("true"))) { + reqValShowProp = true; + } + if ((req.getParameter(WebAdminConstants.REQ_PAR_SHOW_ACTV) != null) + && (req.getParameter(WebAdminConstants.REQ_PAR_SHOW_ACTV) + .equals("true"))) { + reqValShowActv = true; + } + } + + /** + * Retrieve the selected configuration property's values + * + * @param req + */ + private static void retrieveSelectedConfigurationPropertyValues( + HttpServletRequest req) { + if ((reqValAction.equals(WebAdminConstants.ACT_VAL_CON_ADD_PROP)) + || (reqValAction.equals(WebAdminConstants.ACT_VAL_REQ_UPD_PROP)) + || (reqValAction.equals(WebAdminConstants.ACT_VAL_CON_REM_PROP))) { + // Name, description, type and value + reqValPropName = req.getParameter(WebAdminConstants.REQ_PAR_PROP_NAME); + reqValPropDescr = req.getParameter(WebAdminConstants.REQ_PAR_PROP_DESC); + reqValPropType = req.getParameter(WebAdminConstants.REQ_PAR_PROP_TYPE); + reqValPropValue = req + .getParameter(WebAdminConstants.REQ_PAR_PROP_VALUE); + } + } + + /** + * Plug-in install and uninstall request + */ + private static void processPluginInstallRequests() { + if (reqValAction.equals(WebAdminConstants.ACT_VAL_INSTALL)) { + if (sobjPA.installPlugin(reqValHashcode) == false) { + e.append("Plug-in can not be installed!" + + " Check log for details."); + } + // Persist the DB changes + else { + PluginInfo pInfo = sobjPA.getPluginInfo(reqValHashcode); + sobjPA.pluginUpdated(sobjPA.getPlugin(pInfo)); + } + } else if (reqValAction.equals(WebAdminConstants.ACT_VAL_UNINSTALL)) { + if (sobjPA.uninstallPlugin(reqValHashcode) == false) { + e.append("Plug-in can not be uninstalled." + + " Check log for details."); + } else { + e.append("A job was scheduled to remove the plug-in"); + } + } + } + + /** + * Plug-in's configuration property removal + */ + private static void removePluginConfigurationProperty() { + if (selPI.hasConfProp(reqValPropName, reqValPropType)) { + try { + if (selPI.removeConfigEntry(sobjDB, reqValPropName, + reqValPropType)) { + // Update the Plug-in Admin's information + sobjPA.pluginUpdated(sobjPA.getPlugin(selPI)); + // Reload the PluginInfo object + selPI = sobjPA.getPluginInfo(reqValHashcode); + } else { + e.append("Property removal" + " has failed!" + + " Check log for details."); + } + } catch (Exception ex) { + e.append(ex.getMessage()); + } + } else { + e.append("Unknown configuration property!"); + } + // Return to the update view upon error + if (e.toString().length() > 0) { + reqValAction = WebAdminConstants.ACT_VAL_REQ_UPD_PROP; + } + } + + /** + * Plug-in's configuration property update + */ + private static void updatePluginConfigurationProperty() { + try { + if (selPI + .updateConfigEntry(sobjDB, reqValPropName, reqValPropValue)) { + // Update the Plug-in Admin's information + sobjPA.pluginUpdated(sobjPA.getPlugin(selPI)); + // Reload the PluginInfo object + selPI = sobjPA.getPluginInfo(reqValHashcode); + } else { + e.append("Property update" + " has failed!" + + " Check log for details."); + } + } catch (Exception ex) { + e.append(ex.getMessage()); + } + } + + private static void createPluginConfigurationProperty() { + try { + if (selPI.addConfigEntry(sobjDB, reqValPropName, reqValPropDescr, + reqValPropType, reqValPropValue)) { + // Update the Plug-in Admin's information + sobjPA.pluginUpdated(sobjPA.getPlugin(selPI)); + // Reload the PluginInfo object + selPI = sobjPA.getPluginInfo(reqValHashcode); + } else { + e.append("Property creation" + " has failed!" + + " Check log for details."); + } + } catch (Exception ex) { + e.append(ex.getMessage()); + } + } } -//vi: ai nosi sw=4 ts=4 expandtab +// vi: ai nosi sw=4 ts=4 expandtab diff --git a/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/ProjectDeleteJob.java b/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/ProjectDeleteJob.java index dcdda445d..452637b14 100644 --- a/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/ProjectDeleteJob.java +++ b/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/ProjectDeleteJob.java @@ -43,14 +43,16 @@ import eu.sqooss.service.db.ProjectVersion; import eu.sqooss.service.db.StoredProject; import eu.sqooss.service.db.StoredProjectConfig; +import eu.sqooss.service.pa.PluginAdmin; import eu.sqooss.service.scheduler.Job; - +//TODO add description public class ProjectDeleteJob extends Job { private StoredProject sp; private AlitheiaCore core; - - ProjectDeleteJob(AlitheiaCore core, StoredProject sp) { + + //TODO added public in constructor for testing purposes + public ProjectDeleteJob(AlitheiaCore core, StoredProject sp) { this.sp = sp; this.core = core; } @@ -60,16 +62,18 @@ public long priority() { return 0xff; } + //TODO remove suppressed warnings + //TODO remove excess code @SuppressWarnings("unchecked") @Override protected void run() throws Exception { - DBService dbs = core.getDBService(); + DBService dbs = core.getDBService(); if (!dbs.isDBSessionActive()) { dbs.startDBSession(); } - sp = dbs.attachObjectToDBSession(sp); + sp = dbs.attachObjectToDBSession(sp); // Delete any associated invocation rules first HashMap properties = new HashMap(); properties.put("project", sp); @@ -77,15 +81,11 @@ protected void run() throws Exception { //Cleanup plugin results List ps = (List) dbs.doHQL("from Plugin"); + PluginAdmin pa = core.getPluginAdmin(); for (Plugin p : ps ) { - AlitheiaPlugin ap = core.getPluginAdmin().getPlugin(core.getPluginAdmin().getPluginInfo(p.getHashcode())); - if (ap == null) { - //logger.warn("Plugin with hashcode: "+ p.getHashcode() + - // " not installed"); - continue; - } - - ap.cleanup(sp); + AlitheiaPlugin ap = pa.getPlugin(pa.getPluginInfo(p.getHashcode())); + if (ap != null) + ap.cleanup(sp); } boolean success = true; @@ -105,7 +105,7 @@ protected void run() throws Exception { List confParams = StoredProjectConfig.fromProject(sp); if (!confParams.isEmpty()) { success &= dbs.deleteRecords(confParams); - } + } // Delete the selected project success &= dbs.deleteRecord(sp); diff --git a/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/ProjectsView.java b/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/ProjectsView.java index 2975b36d6..79fe5eeca 100644 --- a/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/ProjectsView.java +++ b/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/ProjectsView.java @@ -33,8 +33,8 @@ package eu.sqooss.impl.service.webadmin; -import java.util.Collection; -import java.util.HashMap; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Set; @@ -43,7 +43,6 @@ import org.apache.velocity.VelocityContext; import org.osgi.framework.BundleContext; -import eu.sqooss.core.AlitheiaCore; import eu.sqooss.service.abstractmetric.AlitheiaPlugin; import eu.sqooss.service.admin.AdminAction; import eu.sqooss.service.admin.AdminService; @@ -58,34 +57,14 @@ import eu.sqooss.service.scheduler.SchedulerException; import eu.sqooss.service.updater.Updater; import eu.sqooss.service.updater.UpdaterService.UpdaterStage; +import eu.sqooss.service.util.StringUtils; public class ProjectsView extends AbstractView { - // Script for submitting this page - private static String SUBMIT = "document.projects.submit();"; - - // Action parameter's values - private static String ACT_REQ_ADD_PROJECT = "reqAddProject"; - private static String ACT_CON_ADD_PROJECT = "conAddProject"; - private static String ACT_REQ_REM_PROJECT = "reqRemProject"; - private static String ACT_CON_REM_PROJECT = "conRemProject"; - private static String ACT_REQ_SHOW_PROJECT = "conShowProject"; - private static String ACT_CON_UPD_ALL = "conUpdateAll"; - private static String ACT_CON_UPD = "conUpdate"; - private static String ACT_CON_UPD_ALL_NODE = "conUpdateAllOnNode"; - - // Servlet parameters - private static String REQ_PAR_ACTION = "reqAction"; - private static String REQ_PAR_PROJECT_ID = "projectId"; - private static String REQ_PAR_PRJ_NAME = "projectName"; - private static String REQ_PAR_PRJ_WEB = "projectHomepage"; - private static String REQ_PAR_PRJ_CONT = "projectContact"; - private static String REQ_PAR_PRJ_BUG = "projectBL"; - private static String REQ_PAR_PRJ_MAIL = "projectML"; - private static String REQ_PAR_PRJ_CODE = "projectSCM"; - private static String REQ_PAR_SYNC_PLUGIN = "reqParSyncPlugin"; - private static String REQ_PAR_UPD = "reqUpd"; - /** + private ArrayList errors = new ArrayList(); + private StoredProject selProject; + + /** * Instantiates a new projects view. * * @param bundlecontext the BundleContext object @@ -94,81 +73,69 @@ public class ProjectsView extends AbstractView { public ProjectsView(BundleContext bundlecontext, VelocityContext vc) { super(bundlecontext, vc); } - - /** - * Renders the various project's views. - * - * @param req the servlet's request object - * - * @return The HTML presentation of the generated view. - */ - public static String render(HttpServletRequest req) { - // Stores the assembled HTML content - StringBuilder b = new StringBuilder("\n"); - // Stores the accumulated error messages - StringBuilder e = new StringBuilder(); - // Indentation spacer - int in = 6; + + public StoredProject getSelProject() { + return selProject; + } + + public void exec(HttpServletRequest req) { // Initialize the resource bundles with the request's locale initResources(req.getLocale()); - + // Request values String reqValAction = ""; Long reqValProjectId = null; + + //Delete old errors + errors.clear(); - // Selected project - StoredProject selProject = null; - - // =============================================================== - // Parse the servlet's request object - // =============================================================== - if (req != null) { - // DEBUG: Dump the servlet's request parameter - if (DEBUG) { - b.append(debugRequest(req)); - } - // Retrieve the selected editor's action (if any) - reqValAction = req.getParameter(REQ_PAR_ACTION); - - // Retrieve the selected project's DAO (if any) - reqValProjectId = fromString(req.getParameter(REQ_PAR_PROJECT_ID)); - if (reqValProjectId != null) { - selProject = sobjDB.findObjectById( - StoredProject.class, reqValProjectId); - } - - if (reqValAction == null) { - reqValAction = ""; - } else if (reqValAction.equals(ACT_CON_ADD_PROJECT)) { - selProject = addProject(e, req, in); - } else if (reqValAction.equals(ACT_CON_REM_PROJECT)) { - selProject = removeProject(e, selProject, in); - } else if (reqValAction.equals(ACT_CON_UPD)) { - triggerUpdate(e, selProject, in, req.getParameter(REQ_PAR_UPD)); - } else if (reqValAction.equals(ACT_CON_UPD_ALL)) { - triggerAllUpdate(e, selProject, in); - } else if (reqValAction.equals(ACT_CON_UPD_ALL_NODE)) { - triggerAllUpdateNode(e, selProject, in); - } else { - // Retrieve the selected plug-in's hash-code - String reqValSyncPlugin = req.getParameter(REQ_PAR_SYNC_PLUGIN); - syncPlugin(e, selProject, reqValSyncPlugin); - } + // Retrieve the selected editor's action (if any) + reqValAction = req.getParameter(WebAdminConstants.REQ_PAR_ACTION); + + // Retrieve the selected project's DAO (if any) + selProject = null; + reqValProjectId = fromString(req.getParameter(WebAdminConstants.REQ_PAR_PROJECT_ID)); + if (reqValProjectId != null) { + selProject = sobjDB.findObjectById(StoredProject.class, reqValProjectId); + } + + if (reqValAction != null) { + if (reqValAction.equals(WebAdminConstants.ACT_CON_ADD_PROJECT)) { + selProject = addProject(req); + } else if (reqValAction.equals(WebAdminConstants.ACT_CON_REM_PROJECT)) { + removeProject(selProject); + this.selProject = null; + } else if (reqValAction.equals(WebAdminConstants.ACT_CON_UPD)) { + triggerUpdate(selProject, req.getParameter(WebAdminConstants.REQ_PAR_UPD)); + } else if (reqValAction.equals(WebAdminConstants.ACT_CON_UPD_ALL)) { + triggerUpdate(selProject); + } else if (reqValAction.equals(WebAdminConstants.ACT_CON_UPD_ALL_NODE)) { + triggerAllUpdateNode(); + } else { + // Retrieve the selected plug-in's hash-code + String reqValSyncPlugin = req.getParameter(WebAdminConstants.REQ_PAR_SYNC_PLUGIN); + syncPlugin(selProject, reqValSyncPlugin); + } } - createFrom(b, e, selProject, reqValAction , in); - return b.toString(); } - - private static StoredProject addProject(StringBuilder e, HttpServletRequest r, int indent) { - AdminService as = AlitheiaCore.getInstance().getAdminService(); + + /** + * Creates a new stored project based on the request parameters + * + * @param request Request sent to the server + * @return the newly created stored project + */ + private StoredProject addProject(HttpServletRequest request) { + + AdminService as = sobjCore.getAdminService(); AdminAction aa = as.create(AddProject.MNEMONIC); - aa.addArg("scm", r.getParameter(REQ_PAR_PRJ_CODE)); - aa.addArg("name", r.getParameter(REQ_PAR_PRJ_NAME)); - aa.addArg("bts", r.getParameter(REQ_PAR_PRJ_BUG)); - aa.addArg("mail", r.getParameter(REQ_PAR_PRJ_MAIL)); - aa.addArg("web", r.getParameter(REQ_PAR_PRJ_WEB)); + aa.addArg("scm", request.getParameter(WebAdminConstants.REQ_PAR_PRJ_CODE)); + aa.addArg("name", request.getParameter(WebAdminConstants.REQ_PAR_PRJ_NAME)); + aa.addArg("bts", request.getParameter(WebAdminConstants.REQ_PAR_PRJ_BUG)); + aa.addArg("mail", request.getParameter(WebAdminConstants.REQ_PAR_PRJ_MAIL)); + aa.addArg("web", request.getParameter(WebAdminConstants.REQ_PAR_PRJ_WEB)); as.execute(aa); if (aa.hasErrors()) { @@ -176,40 +143,42 @@ private static StoredProject addProject(StringBuilder e, HttpServletRequest r, i return null; } else { vc.put("RESULTS", aa.results()); - return StoredProject.getProjectByName(r.getParameter(REQ_PAR_PRJ_NAME)); - } + return StoredProject.getProjectByName(request.getParameter(WebAdminConstants.REQ_PAR_PRJ_NAME)); + } } - // --------------------------------------------------------------- - // Remove project - // --------------------------------------------------------------- - private static StoredProject removeProject(StringBuilder e, - StoredProject selProject, int indent) { - if (selProject != null) { - // Deleting large projects in the foreground is - // very slow - ProjectDeleteJob pdj = new ProjectDeleteJob(sobjCore, selProject); + /** + * Queues a job in the scheduler for deleting a project + * + * @param project the project to be deleted + */ + private void removeProject(StoredProject project) { + if (project != null) { + // Deleting large projects in the foreground is very slow + ProjectDeleteJob pdj = new ProjectDeleteJob(sobjCore, project); try { sobjSched.enqueue(pdj); } catch (SchedulerException e1) { - e.append(sp(indent)).append(getErr("e0034")).append("
\n"); + errors.add(getErr("e0034")); } - selProject = null; } else { - e.append(sp(indent) + getErr("e0034") + "
\n"); + errors.add(getErr("e0034")); } - return selProject; } - // --------------------------------------------------------------- - // Trigger an update - // --------------------------------------------------------------- - private static void triggerUpdate(StringBuilder e, - StoredProject selProject, int indent, String mnem) { - AdminService as = AlitheiaCore.getInstance().getAdminService(); + + /** + * Triggers an update on a project + * + * @param project the project which to update + * @param mnem string determining the update to perform + */ + private void triggerUpdate(StoredProject project, String mnem) { + AdminService as = sobjCore.getAdminService(); AdminAction aa = as.create(UpdateProject.MNEMONIC); - aa.addArg("project", selProject.getId()); - aa.addArg("updater", mnem); + aa.addArg("project", project.getId()); + if(mnem != null) + aa.addArg("updater", mnem); as.execute(aa); if (aa.hasErrors()) { @@ -219,457 +188,187 @@ private static void triggerUpdate(StringBuilder e, } } - // --------------------------------------------------------------- - // Trigger update on all resources for that project - // --------------------------------------------------------------- - private static void triggerAllUpdate(StringBuilder e, - StoredProject selProject, int indent) { - AdminService as = AlitheiaCore.getInstance().getAdminService(); - AdminAction aa = as.create(UpdateProject.MNEMONIC); - aa.addArg("project", selProject.getId()); - as.execute(aa); - - if (aa.hasErrors()) { - vc.put("RESULTS", aa.errors()); - } else { - vc.put("RESULTS", aa.results()); - } + /** + * Trigger update on all resources for that project + * + * @param project the project to trigger the update on + */ + private void triggerUpdate(StoredProject project) { + triggerUpdate(project, null); } - // --------------------------------------------------------------- - // Trigger update on all resources on all projects of a node - // --------------------------------------------------------------- - private static void triggerAllUpdateNode(StringBuilder e, - StoredProject selProject, int in) { + /** + * Trigger update on all resources on all projects of this node + */ + private void triggerAllUpdateNode() { Set projectList = ClusterNode.thisNode().getProjects(); for (StoredProject project : projectList) { - triggerAllUpdate(e, project, in); + triggerUpdate(project); } } - // --------------------------------------------------------------- - // Trigger synchronize on the selected plug-in for that project - // --------------------------------------------------------------- - private static void syncPlugin(StringBuilder e, StoredProject selProject, String reqValSyncPlugin) { - if ((reqValSyncPlugin != null) && (selProject != null)) { + /** + * Trigger synchronize on the selected plug-in for that project + * + * @param project the selected project + * @param reqValSyncPlugin the plugin to trigger the update on + */ + private void syncPlugin(StoredProject project, String reqValSyncPlugin) { + if ((reqValSyncPlugin != null) && (project != null)) { PluginInfo pInfo = sobjPA.getPluginInfo(reqValSyncPlugin); if (pInfo != null) { AlitheiaPlugin pObj = sobjPA.getPlugin(pInfo); if (pObj != null) { - compMA.syncMetric(pObj, selProject); + compMA.syncMetric(pObj, project); sobjLogger.debug("Syncronise plugin (" + pObj.getName() - + ") on project (" + selProject.getName() + ")."); + + ") on project (" + project.getName() + ")."); } } } } + + /** + * Retrieves the errors encountered during the processing of the request + * + * @return list with errors + */ + public List getErrors() { + ArrayList htmlErrors = new ArrayList(); + for (String error : errors) + htmlErrors.add(StringUtils.makeXHTMLSafe(error)); + + return htmlErrors; + } - private static void createFrom(StringBuilder b, StringBuilder e, - StoredProject selProject, String reqValAction, int in) { - - // =============================================================== - // Create the form - // =============================================================== - b.append(sp(in) + "
\n"); - - // =============================================================== - // Display the accumulated error messages (if any) - // =============================================================== - b.append(errorFieldset(e, ++in)); - - // Get the complete list of projects stored in the SQO-OSS framework - Set projects = ClusterNode.thisNode().getProjects(); - Collection metrics = sobjPA.listPlugins(); - - // =================================================================== - // "Show project info" view - // =================================================================== - if ((reqValAction.equals(ACT_REQ_SHOW_PROJECT)) - && (selProject != null)) { - // Create the field-set - b.append(sp(in++) + "
\n"); - b.append(sp(in) + "" - + "Project information" - + "\n"); - b.append(sp(in++) + "\n"); - // Create the input fields - b.append(normalInfoRow( - "Project name", selProject.getName(), in)); - b.append(normalInfoRow( - "Homepage", selProject.getWebsiteUrl(), in)); - b.append(normalInfoRow( - "Contact e-mail", selProject.getContactUrl(), in)); - b.append(normalInfoRow( - "Bug database", selProject.getBtsUrl(), in)); - b.append(normalInfoRow( - "Mailing list", selProject.getMailUrl(), in)); - b.append(normalInfoRow( - "Source code", selProject.getScmUrl(), in)); - - //------------------------------------------------------------ - // Tool-bar - //------------------------------------------------------------ - b.append(sp(in++) + "\n"); - b.append(sp(in++) - + "\n"); - b.append(sp(--in) + "\n"); - b.append(sp(--in) + "
\n"); - // Back button - b.append(sp(in) + "\n"); - b.append(sp(--in) + "
\n"); - b.append(sp(--in) + "
\n"); - } - // =================================================================== - // "Add project" editor - // =================================================================== - else if (reqValAction.equals(ACT_REQ_ADD_PROJECT)) { - // Create the field-set - b.append(sp(in++) + "\n"); - // Create the input fields - b.append(normalInputRow( - "Project name", REQ_PAR_PRJ_NAME, "", in)); - b.append(normalInputRow( - "Homepage", REQ_PAR_PRJ_WEB, "", in)); - b.append(normalInputRow( - "Contact e-mail", REQ_PAR_PRJ_CONT, "", in)); - b.append(normalInputRow( - "Bug database", REQ_PAR_PRJ_BUG, "", in)); - b.append(normalInputRow( - "Mailing list", REQ_PAR_PRJ_MAIL, "", in)); - b.append(normalInputRow( - "Source code", REQ_PAR_PRJ_CODE, "", in)); - - //------------------------------------------------------------ - // Tool-bar - //------------------------------------------------------------ - b.append(sp(in++) + "\n"); - b.append(sp(in++) - + "\n"); - b.append(sp(--in) + "\n"); - b.append(sp(--in) + "
\n"); - // Apply button - b.append(sp(in) + "\n"); - // Cancel button - b.append(sp(in) + "\n"); - b.append(sp(--in) + "
\n"); - } - // =================================================================== - // "Delete project" confirmation view - // =================================================================== - else if ((reqValAction.equals(ACT_REQ_REM_PROJECT)) - && (selProject != null)) { - b.append(sp(in++) + "
\n"); - b.append(sp(in) + "" + getLbl("l0059") - + ": " + selProject.getName() - + "\n"); - b.append(sp(in++) + ""); - // Confirmation message - b.append(sp(in++) + "\n"); - b.append(sp(in) + "\n"); - - b.append(sp(--in) + "\n"); - //------------------------------------------------------------ - // Tool-bar - //------------------------------------------------------------ - b.append(sp(in++) + "\n"); - b.append(sp(in++) - + "\n"); - b.append(sp(--in) + "\n"); - b.append(sp(--in) + "
" - + "" + getMsg("delete_project") + "" - + "
\n"); - // Confirm button - b.append(sp(in) + "\n"); - // Cancel button - b.append(sp(in) + "\n"); - b.append(sp(--in) + "
"); - b.append(sp(in) + "
\n"); - } - // =================================================================== - // Projects list view - // =================================================================== - else { - addHeaderRow(b,in); - - if (projects.isEmpty()) { - b.append(sp(in++) + "\n"); - b.append(sp(in) + "\n" - + getMsg("no_projects") - + "\n"); - b.append(sp(--in) + "\n"); - } - else { - //------------------------------------------------------------ - // Create the content rows - //------------------------------------------------------------ - b.append(sp(in++) + "\n"); - for (StoredProject nextPrj : projects) { - boolean selected = false; - if ((selProject != null) - && (selProject.getId() == nextPrj.getId())) { - selected = true; - } - b.append(sp(in++) + "\n"); - // Project Id - b.append(sp(in) + "" - + nextPrj.getId() - + "\n"); - // Project name - b.append(sp(in) + "" - + ((selected) - ? "" - : "\"[Edit]\"/") - + " " - + nextPrj.getName() - + "\n"); - // Last project version - String lastVersion = getLbl("l0051"); - ProjectVersion v = ProjectVersion.getLastProjectVersion(nextPrj); - if (v != null) { - lastVersion = String.valueOf(v.getSequence()) + "(" + v.getRevisionId() + ")"; - } - b.append(sp(in) + "" - + lastVersion - + "\n"); - // Date of the last known email - MailMessage mm = MailMessage.getLatestMailMessage(nextPrj); - b.append(sp(in) + "" - + ((mm == null)?getLbl("l0051"):mm.getSendDate()) - + "\n"); - // ID of the last known bug entry - Bug bug = Bug.getLastUpdate(nextPrj); - b.append(sp(in) + "" - + ((bug == null)?getLbl("l0051"):bug.getBugID()) - + "\n"); - // Evaluation state - String evalState = getLbl("project_not_evaluated"); - if (nextPrj.isEvaluated()) { - evalState = getLbl("project_is_evaluated"); - } - b.append(sp(in) + "" - + evalState - + "\n"); - - // Cluster node - String nodename = null; - if (null != nextPrj.getClusternode()) { - nodename = nextPrj.getClusternode().getName(); - } else { - nodename = "(local)"; - } - b.append(sp(in) + "" + nodename + "\n"); - b.append(sp(--in) + "\n"); - if ((selected) && (metrics.isEmpty() == false)) { - showLastAppliedVersion(nextPrj, metrics, b); - } - } - } - //---------------------------------------------------------------- - // Tool-bar - //---------------------------------------------------------------- - addToolBar(selProject,b,in); - - //---------------------------------------------------------------- - // Close the table - //---------------------------------------------------------------- - b.append(sp(--in) + "\n"); - b.append(sp(--in) + "\n"); - b.append(sp(--in) + "\n"); - } - - // =============================================================== - // INPUT FIELDS - // =============================================================== - addHiddenFields(selProject,b,in); - - // =============================================================== - // Close the form - // =============================================================== - b.append(sp(--in) + "\n"); + /** + * Retrieves all the projects on the local node + * + * @return set with projects + */ + public static Set getProjects() { + return ClusterNode.thisNode().getProjects(); } - - - private static void addHiddenFields(StoredProject selProject, - StringBuilder b, - long in) { - // "Action type" input field - b.append(sp(in) + "\n"); - // "Project Id" input field - b.append(sp(in) + "\n"); - // "Plug-in hashcode" input field - b.append(sp(in) + "\n"); + + /** + * Retrieves the latest project version of a project + * + * @param project + * @return String representation of the latest version + */ + public static String getLastProjectVersion(StoredProject project) { + String lastVersion = getLbl("l0051"); + if(project != null) { + ProjectVersion v = ProjectVersion.getLastProjectVersion(project); + if (v != null) { + lastVersion = String.valueOf(v.getSequence()) + "(" + v.getRevisionId() + ")"; + } + } + return lastVersion; } - private static void addToolBar(StoredProject selProject, - StringBuilder b, - long in) { - b.append(sp(in++) + "\n"); - b.append(sp(in++) + "View\n"); - // Refresh button - b.append(sp(in) + ""); - b.append("Manage\n"); - // Add project button - b.append(sp(in) + "\n"); - // Remove project button - b.append(sp(in) + ""); - b.append("Update\n"); - - if (selProject != null) { - b.append(sp(in) + ""); - } - - // Trigger updater - b.append(sp(in) + "\n"); - // Trigger all updates - b.append(sp(in) + "\n"); - b.append(sp(--in) + "\n"); - b.append(sp(--in) + "\n"); - // Trigger updates on host - b.append(sp(in) + "\n"); - b.append(sp(--in) + "\n"); - b.append(sp(--in) + "\n"); + /** + * Retrieves the latest email date of a project + * + * @param project + * @return String representation of the latest date an email was sent + */ + public static String getLastEmailDate(StoredProject project) { + String lastDate = getLbl("l0051"); + if(project != null) { + MailMessage mm = MailMessage.getLatestMailMessage(project); + if (mm != null) { + lastDate = mm.getSendDate().toString(); + } + } + return lastDate; } - private static void showLastAppliedVersion( - StoredProject project, - Collection metrics, - StringBuilder b) { - for(PluginInfo m : metrics) { - if (m.installed) { - b.append("\n"); - b.append(sp(1) + "\n" - + "" - + " " - + m.getPluginName() - + "\n"); - b.append("\n"); - } - } + /** + * Retrieves the last bug of a project + * + * @param project + * @return String representation of the ID of the last bug filed for the project + */ + public static String getLastBug(StoredProject project) { + String lastBug = getLbl("l0051"); + if(project != null) { + Bug bug = Bug.getLastUpdate(project); + if (bug != null) { + lastBug = bug.getBugID(); + } + } + return lastBug; + } + + /** + * Retrieves the current state of evaluation of a project + * + * @param project + * @return String representation of the project evaluation state + */ + public static String getEvalState(StoredProject project) { + String evalState = getLbl("project_not_evaluated"); + if(project != null) { + if (project.isEvaluated()) { + evalState = getLbl("project_is_evaluated"); + } + } + return evalState; + } + + /** + * Retrieves the node on which a project runs + * + * @param project + * @return name of the cluster node (String) + */ + public static String getClusternode(StoredProject project) { + String nodename = getLbl("l0051"); + if(project != null) { + if (project.getClusternode() != null) { + nodename = project.getClusternode().getName(); + } else { + nodename = "(local)"; + } + } + return nodename; } - private static void addHeaderRow(StringBuilder b, long in) { - //---------------------------------------------------------------- - // Create the header row - //---------------------------------------------------------------- - b.append(sp(in++) + "\n"); - b.append(sp(in++) + "\n"); - b.append(sp(in++) + "\n"); - b.append(sp(in) + "\n"); - b.append(sp(in) + "\n"); - b.append(sp(in) + "\n"); - b.append(sp(in) + "\n"); - b.append(sp(in) + "\n"); - b.append(sp(in) + "\n"); - b.append(sp(in) + "\n"); - b.append(sp(--in) + "\n"); - b.append(sp(--in) + "\n"); + /** + * Retrieves the updaters of a specific project + * + * @param project + * @param updaterStage desired state of the updater + * @return a set with all updaters of a specific project in a specific state + */ + public static Set getUpdaters(StoredProject project, String updaterStage) { + Set updaters; + + UpdaterStage stage; + if(updaterStage == "inference") + stage = UpdaterStage.INFERENCE; + else if(updaterStage == "import") + stage = UpdaterStage.IMPORT; + else if(updaterStage == "parse") + stage = UpdaterStage.PARSE; + else + stage = UpdaterStage.DEFAULT; + + if(project != null) + updaters = sobjUpdater.getUpdaters(project, stage); + else + updaters = Collections.emptySet(); + return updaters; + } + + /** + * Retrieves the name of this cluster + * + * @return String with the name + */ + public static String getClusterName() { + return sobjClusterNode.getClusterNodeName(); } } diff --git a/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/ResultsView.java b/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/ResultsView.java new file mode 100644 index 000000000..bb0258b2b --- /dev/null +++ b/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/ResultsView.java @@ -0,0 +1,52 @@ +package eu.sqooss.impl.service.webadmin; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.velocity.VelocityContext; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleException; + +import eu.sqooss.core.AlitheiaCore; +import eu.sqooss.service.admin.AdminAction; +import eu.sqooss.service.admin.AdminService; +import eu.sqooss.service.admin.actions.AddProject; + +public class ResultsView extends AbstractView { + + public ResultsView(BundleContext bundlecontext, VelocityContext vc) { + super(bundlecontext, vc); + } + + @Override + public void exec(HttpServletRequest req) { + String query = req.getPathInfo(); + + if (query.startsWith("/stop")) { + vc.put("RESULTS", "

Alitheia Core is now shutdown.

"); + + // Now stop the system + sobjLogger.info("System stopped by user request to webadmin."); + try { + bc.getBundle(0).stop(); + } catch (BundleException be) { + sobjLogger.warn("Could not stop bundle 0."); + // And ignore + } + } else if (query.startsWith("/restart")) { + vc.put("RESULTS", "

Alitheia Core is now restarting.

"); + //FIXME: How do we do a restart? + } else if (query.startsWith("/addproject")) { + //addProject(request); + } else if (query.startsWith("/diraddproject")) { + AdminService as = sobjCore.getAdminService(); + AdminAction aa = as.create(AddProject.MNEMONIC); + aa.addArg("dir", req.getParameter("properties")); + as.execute(aa); + if (aa.hasErrors()) + vc.put("RESULTS", aa.errors()); + else + vc.put("RESULTS", aa.results()); + } + } + +} diff --git a/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/RulesView.java b/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/RulesView.java new file mode 100644 index 000000000..c4e70529f --- /dev/null +++ b/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/RulesView.java @@ -0,0 +1,18 @@ +package eu.sqooss.impl.service.webadmin; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.velocity.VelocityContext; +import org.osgi.framework.BundleContext; + +public class RulesView extends AbstractView { + + public RulesView(BundleContext bundlecontext, VelocityContext vc) { + super(bundlecontext, vc); + } + + @Override + public void exec(HttpServletRequest req) { + + } +} diff --git a/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/WebAdminConstants.java b/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/WebAdminConstants.java new file mode 100644 index 000000000..cc30cf39e --- /dev/null +++ b/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/WebAdminConstants.java @@ -0,0 +1,49 @@ +package eu.sqooss.impl.service.webadmin; + +public interface WebAdminConstants { + /////////////// + /// PLUGINS /// + /////////////// + // Request parameters + public static final String REQ_PAR_ACTION = "action"; + public static final String REQ_PAR_HASHCODE = "pluginHashcode"; + public static final String REQ_PAR_PROP_NAME = "propertyName"; + public static final String REQ_PAR_PROP_DESC = "propertyDescription"; + public static final String REQ_PAR_PROP_TYPE = "propertyType"; + public static final String REQ_PAR_PROP_VALUE = "propertyValue"; + public static final String REQ_PAR_SHOW_PROP = "showProperties"; + public static final String REQ_PAR_SHOW_ACTV = "showActivators"; + // Recognized "action" parameter's values + public static final String ACT_VAL_INSTALL = "installPlugin"; + public static final String ACT_VAL_UNINSTALL = "uninstallPlugin"; + public static final String ACT_VAL_SYNC = "syncPlugin"; + public static final String ACT_VAL_REQ_ADD_PROP = "createProperty"; + public static final String ACT_VAL_REQ_UPD_PROP = "updateProperty"; + public static final String ACT_VAL_CON_ADD_PROP = "confirmProperty"; + public static final String ACT_VAL_CON_REM_PROP = "removeProperty"; + + //////////////// + /// PROJECTS /// + //////////////// + // Action parameter's values + public static final String ACT_REQ_ADD_PROJECT = "reqAddProject"; + public static final String ACT_CON_ADD_PROJECT = "conAddProject"; + public static final String ACT_REQ_REM_PROJECT = "reqRemProject"; + public static final String ACT_CON_REM_PROJECT = "conRemProject"; + public static final String ACT_REQ_SHOW_PROJECT = "conShowProject"; + public static final String ACT_CON_UPD_ALL = "conUpdateAll"; + public static final String ACT_CON_UPD = "conUpdate"; + public static final String ACT_CON_UPD_ALL_NODE = "conUpdateAllOnNode"; + + // Servlet parameters + public static final String REQ_PROJECT_PAR_ACTION= "reqAction"; + public static final String REQ_PAR_PROJECT_ID = "projectId"; + public static final String REQ_PAR_PRJ_NAME = "projectName"; + public static final String REQ_PAR_PRJ_WEB = "projectHomepage"; + public static final String REQ_PAR_PRJ_CONT = "projectContact"; + public static final String REQ_PAR_PRJ_BUG = "projectBL"; + public static final String REQ_PAR_PRJ_MAIL = "projectML"; + public static final String REQ_PAR_PRJ_CODE = "projectSCM"; + public static final String REQ_PAR_SYNC_PLUGIN = "reqParSyncPlugin"; + public static final String REQ_PAR_UPD = "reqUpd"; +} diff --git a/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/WebAdminRenderer.java b/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/WebAdminRenderer.java deleted file mode 100644 index 9c5a1daea..000000000 --- a/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/WebAdminRenderer.java +++ /dev/null @@ -1,267 +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.impl.service.webadmin; - -import java.util.Date; -import java.util.HashMap; -import java.util.List; - -import org.apache.velocity.VelocityContext; -import org.osgi.framework.BundleContext; - -import eu.sqooss.service.scheduler.Job; -import eu.sqooss.service.util.StringUtils; - -/** - * The WebAdminRender class provides functions for rendering content - * to be displayed within the WebAdmin interface. - * - * @author, Paul J. Adams - * @author, Boryan Yotov - */ -public class WebAdminRenderer extends AbstractView { - /** - * Represents the system time at which the WebAdminRender (and - * thus the system) was started. This is required for the system - * uptime display. - */ - private static long startTime = new Date().getTime(); - - public WebAdminRenderer(BundleContext bundlecontext, VelocityContext vc) { - super(bundlecontext, vc); - } - - /** - * Creates and HTML table displaying the details of all the jobs - * that have failed whilst the system has been up - * - * @return a String representing the HTML table - */ - public static String renderJobFailStats() { - StringBuilder result = new StringBuilder(); - HashMap fjobs = sobjSched.getSchedulerStats().getFailedJobTypes(); - result.append("
" - + getLbl("l0066") - + "" - + getLbl("l0067") - + "" - + getLbl("l0068") - + "" - + getLbl("l0069") - + "" - + getLbl("l0070") - + "" - + getLbl("l0071") - + "" - + getLbl("l0073") - + "
\n"); - result.append("\t\n"); - result.append("\t\t\n"); - result.append("\t\t\t\n"); - result.append("\t\t\t\n"); - result.append("\t\t\n"); - result.append("\t\n"); - result.append("\t\n"); - - String[] jobfailures = fjobs.keySet().toArray(new String[1]); - for(String key : jobfailures) { - result.append("\t\t\n\t\t\t\n\t\t\t\n\t\t"); - } - result.append("\t\n"); - result.append("
Job TypeNum Jobs Failed
"); - result.append(key==null ? "No failures" : key); - result.append(""); - result.append(key==null ? " " : fjobs.get(key)); - result.append("\t\t\t
"); - return result.toString(); - } - - /** - * Creates and HTML table with information about the jobs that - * failed and the recorded exceptions - * @return - */ - public static String renderFailedJobs() { - StringBuilder result = new StringBuilder(); - Job[] jobs = sobjSched.getFailedQueue(); - result.append("\n"); - result.append("\t\n"); - result.append("\t\t\n"); - result.append("\t\t\t\n"); - result.append("\t\t\t\n"); - result.append("\t\t\t\n"); - result.append("\t\t\t\n"); - result.append("\t\t\n"); - result.append("\t\n"); - result.append("\t\n"); - - if ((jobs != null) && (jobs.length > 0)) { - for(Job j: jobs) { - if (j == null) continue; - result.append("\t\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t\t\n\t\t"); - } - } - else { - result.append (""); - } - result.append("\t\n"); - result.append("
Job TypeException typeException textException backtrace
"); - if (j.getClass() != null) { - try { - //result.append(j.getClass().getPackage().getName()); - //result.append(". " + j.getClass().getSimpleName()); - result.append(j.toString()); - } - catch (NullPointerException ex) { - result.append("NA"); - } - } - else { - result.append("NA"); - } - result.append(""); - Exception e = j.getErrorException(); - if (e != null) { - try { - result.append(e.getClass().getPackage().getName()); - result.append(". " + e.getClass().getSimpleName()); - } - catch (NullPointerException ex) { - result.append("NA"); - } - } - else { - result.append("NA"); - } - result.append(""); - try { - result.append(e.getMessage()); - } - catch (NullPointerException ex) { - result.append("NA"); - } - result.append(""); - if ((e != null) - && (e.getStackTrace() != null)) { - for(StackTraceElement m: e.getStackTrace()) { - if (m == null) continue; - result.append(m.getClassName()); - result.append(". "); - result.append(m.getMethodName()); - result.append("(), ("); - result.append(m.getFileName()); - result.append(":"); - result.append(m.getLineNumber()); - result.append(")
"); - } - } - else { - result.append("NA"); - } - result.append("\t\t\t
No failed jobs.
"); - - return result.toString(); - } - - /** - * Creates an HTML unordered list displaying the contents of the current system log - * - * @return a String representing the HTML unordered list items - */ - public static String renderLogs() { - String[] names = sobjLogManager.getRecentEntries(); - - if ((names != null) && (names.length > 0)) { - StringBuilder b = new StringBuilder(); - for (String s : names) { - b.append("\t\t\t\t\t
  • " + StringUtils.makeXHTMLSafe(s) + "
  • \n"); - } - - return b.toString(); - } else { - return "\t\t\t\t\t
  • <none>
  • \n"; - } - } - - /** - * Returns a string representing the uptime of the Alitheia core - * in dd:hh:mm:ss format - */ - public static String getUptime() { - long remainder; - long currentTime = new Date().getTime(); - long timeRunning = currentTime - startTime; - - // Get the elapsed time in days, hours, mins, secs - int days = new Long(timeRunning / 86400000).intValue(); - remainder = timeRunning % 86400000; - int hours = new Long(remainder / 3600000).intValue(); - remainder = remainder % 3600000; - int mins = new Long(remainder / 60000).intValue(); - remainder = remainder % 60000; - int secs = new Long(remainder / 1000).intValue(); - - return String.format("%d:%02d:%02d:%02d", days, hours, mins, secs); - } - - - public static String renderJobWaitStats() { - StringBuilder result = new StringBuilder(); - HashMap wjobs = sobjSched.getSchedulerStats().getWaitingJobTypes(); - result.append("\n"); - result.append("\t\n"); - result.append("\t\t\n"); - result.append("\t\t\t\n"); - result.append("\t\t\t\n"); - result.append("\t\t\n"); - result.append("\t\n"); - result.append("\t\n"); - - String[] jobfailures = wjobs.keySet().toArray(new String[1]); - for(String key : jobfailures) { - result.append("\t\t\n\t\t\t\n\t\t\t\n\t\t"); - } - result.append("\t\n"); - result.append("
    Job TypeNum Jobs Waiting
    "); - result.append(key==null ? "No failures" : key); - result.append(""); - result.append(key==null ? " " : wjobs.get(key)); - result.append("\t\t\t
    "); - return result.toString(); - } - - public static String renderJobRunStats() { - StringBuilder result = new StringBuilder(); - List rjobs = sobjSched.getSchedulerStats().getRunJobs(); - if (rjobs.size() == 0) { - return "No running jobs"; - } - result.append("
      \n"); - for(String s : rjobs) { - result.append("\t
    • "); - result.append(s); - result.append("\t
    • \n"); - } - result.append("
    \n"); - return result.toString(); - } -} - -//vi: ai nosi sw=4 ts=4 expandtab diff --git a/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/WebadminServiceImpl.java b/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/WebadminServiceImpl.java index 975b65d16..b7b3c335f 100644 --- a/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/WebadminServiceImpl.java +++ b/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/WebadminServiceImpl.java @@ -30,7 +30,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ - package eu.sqooss.impl.service.webadmin; import java.util.Hashtable; @@ -45,18 +44,17 @@ import eu.sqooss.service.webadmin.WebadminService; /** - * This is the service which provides a web-based administration - * interface. This user interface is used for the addition and removal - * of projects from Alitheia Core and likewise for metric - * plugins. Users of the WebAdmin interface are also able to receive - * basic system information such as uptime, number of running/failed - * jobs, etc. + * This is the service which provides a web-based administration interface. This + * user interface is used for the addition and removal of projects from Alitheia + * Core and likewise for metric plugins. Users of the WebAdmin interface are + * also able to receive basic system information such as uptime, number of + * running/failed jobs, etc. */ public class WebadminServiceImpl implements WebadminService { /** - * The Velocity Engine is used to to provide services for - * dynamically loading content into the page templates + * The Velocity Engine is used to to provide services for dynamically + * loading content into the page templates */ private VelocityEngine ve; @@ -66,14 +64,15 @@ public class WebadminServiceImpl implements WebadminService { private Logger logger = null; /** - * This String is used to represent the current "message of the - * day" available in the Alitheia Core + * This String is used to represent the current "message of the day" + * available in the Alitheia Core */ private String messageOfTheDay = null; private BundleContext bc; - public WebadminServiceImpl() { } + public WebadminServiceImpl() { + } /** * Retrieves the "message of the day" String @@ -93,71 +92,74 @@ public void setMessageOfTheDay(String s) { messageOfTheDay = s; } - /* - * The utility method used for the initialization of the velocity engine. - */ - private void initVelocity() { - try { - ve = new VelocityEngine(); - ve.setProperty("runtime.log.logsystem.class", - "org.apache.velocity.runtime.log.SimpleLog4JLogSystem"); - ve.setProperty("runtime.log.logsystem.log4j.category", - Logger.NAME_SQOOSS_WEBADMIN); - String resourceLoader = "classpath"; - ve.setProperty(RuntimeConstants.RESOURCE_LOADER, resourceLoader); - ve.setProperty(resourceLoader + "." + RuntimeConstants.RESOURCE_LOADER + ".class", - "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); - } - catch (Exception e) { - logger.error("Velocity initialization",e); - } + @Override + public void setInitParams(BundleContext bc, Logger l) { + this.logger = l; + this.bc = bc; } - @Override - public void setInitParams(BundleContext bc, Logger l) { - this.logger = l; - this.bc = bc; - } - - @Override - public void shutDown() { - } + @Override + public void shutDown() { + } + @SuppressWarnings("rawtypes") @Override - public boolean startUp() { + public boolean startUp() { // Get a reference to the HTTPService, and then its object HttpService sobjHTTPService = null; ServiceReference srefHTTPService = bc.getServiceReference( - HttpService.class.getName()); - + HttpService.class.getName()); + if (srefHTTPService != null) { sobjHTTPService = (HttpService) bc.getService(srefHTTPService); - } - else { + } else { logger.error("Could not find a HTTP service!"); return false; } initVelocity(); - + // Register the front-end servlets if (sobjHTTPService != null) { try { sobjHTTPService.registerServlet( - "/", - new AdminServlet(bc, this, logger, ve), - new Hashtable(), - null); - } - catch (Exception e) { - logger.error("AdminServlet",e); + "/", + makeAdminServlet(bc, this, logger, ve), + new Hashtable(), + null); + } catch (Exception e) { + logger.error("AdminServlet", e); return false; } } return true; - } + } + + /* + * The utility method used for the initialization of the velocity engine. + */ + private void initVelocity() { + try { + ve = new VelocityEngine(); + ve.setProperty("runtime.log.logsystem.class", + "org.apache.velocity.runtime.log.SimpleLog4JLogSystem"); + ve.setProperty("runtime.log.logsystem.log4j.category", + Logger.NAME_SQOOSS_WEBADMIN); + String resourceLoader = "classpath"; + ve.setProperty(RuntimeConstants.RESOURCE_LOADER, resourceLoader); + ve.setProperty(resourceLoader + "." + RuntimeConstants.RESOURCE_LOADER + ".class", + "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader"); + } + catch (Exception e) { + logger.error("Velocity initialization",e); + } + } + + public AdminServlet makeAdminServlet(BundleContext bc, WebadminService service, Logger logger, VelocityEngine ve) { + return new AdminServlet(bc, this, logger, ve); + } + } - // vi: ai nosi sw=4 ts=4 expandtab diff --git a/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/class_diag_webadmin.png b/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/class_diag_webadmin.png new file mode 100644 index 000000000..a9dc6390f Binary files /dev/null and b/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/class_diag_webadmin.png differ diff --git a/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/class_diag_webadmin.ucls b/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/class_diag_webadmin.ucls new file mode 100644 index 000000000..e1de668d7 --- /dev/null +++ b/alitheia/core/src/main/java/eu/sqooss/impl/service/webadmin/class_diag_webadmin.ucls @@ -0,0 +1,210 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/alitheia/core/src/main/java/eu/sqooss/service/abstractmetric/class_diagram_abstractmetric.png b/alitheia/core/src/main/java/eu/sqooss/service/abstractmetric/class_diagram_abstractmetric.png new file mode 100644 index 000000000..4222136bb Binary files /dev/null and b/alitheia/core/src/main/java/eu/sqooss/service/abstractmetric/class_diagram_abstractmetric.png differ diff --git a/alitheia/core/src/main/java/eu/sqooss/service/abstractmetric/class_diagram_abstractmetric.ucls b/alitheia/core/src/main/java/eu/sqooss/service/abstractmetric/class_diagram_abstractmetric.ucls new file mode 100644 index 000000000..09ab275fa --- /dev/null +++ b/alitheia/core/src/main/java/eu/sqooss/service/abstractmetric/class_diagram_abstractmetric.ucls @@ -0,0 +1,277 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/alitheia/core/src/main/java/eu/sqooss/service/db/db_package_diagram.ucls b/alitheia/core/src/main/java/eu/sqooss/service/db/db_package_diagram.ucls new file mode 100644 index 000000000..46775739c --- /dev/null +++ b/alitheia/core/src/main/java/eu/sqooss/service/db/db_package_diagram.ucls @@ -0,0 +1,1688 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/alitheia/core/src/main/java/eu/sqooss/service/pa/PluginInfo.java b/alitheia/core/src/main/java/eu/sqooss/service/pa/PluginInfo.java index 6ea33d4f5..1cd126686 100644 --- a/alitheia/core/src/main/java/eu/sqooss/service/pa/PluginInfo.java +++ b/alitheia/core/src/main/java/eu/sqooss/service/pa/PluginInfo.java @@ -49,561 +49,562 @@ /** * This class holds runtime and configuration information about single metric - * plug-in. - *
    + * plug-in.
    * Usually an instance of a PluginInfo is created from the * PluginAdmin implementation, just after a new metric plug-in - * bundle is installed in the OSGi framework, who registers a metric - * plug-in service. Some of the information provided from the metric - * plug-in object registered with that OSGi service, as well as part of - * the service's information are copied into this new PluginInfo - * instance. + * bundle is installed in the OSGi framework, who registers a metric plug-in + * service. Some of the information provided from the metric plug-in object + * registered with that OSGi service, as well as part of the service's + * information are copied into this new PluginInfo instance. */ public class PluginInfo implements Comparable { - /** - * This enumeration includes all permitted types of configuration values, - * that a metrics can support. The various configuration parameters and - * their values are used mostly from internal metric processes, like - * results rendering and validation. - */ - public enum ConfigurationType { - INTEGER, - STRING, - BOOLEAN, - DOUBLE; - - public static ConfigurationType fromString(String config) { - if (config.equals(BOOLEAN.toString())) - return BOOLEAN; - - if (config.equals(STRING.toString())) - return STRING; - - if (config.equals(INTEGER.toString())) - return INTEGER; - - if (config.equals(DOUBLE.toString())) - return DOUBLE; - - return null; - } - }; - - /** - * The service reference of the service that registered this metric - * plug-in - */ - private ServiceReference serviceRef = null; - - /** - * The name of the associated metric plug-in - */ - private String pluginName = null; - - /** - * The version of the associated metric plug-in - */ - private String pluginVersion = null; - - /** - * This list include all activation interfaces supported by the associated - * metric plug-in. - *
    - * The list of permitted activation interfaces is described in the - * {@link AlitheiaPlugin} interface and currently includes: - *
      - *
    • {@link StoredProjectMetric}
    • - *
    • {@link ProjectVersionMetric}
    • - *
    • {@link ProjectFileMetric}
    • - *
    • {@link FileGroupMetric}
    • - *
    - */ - Set> activationTypes = - new HashSet>(); - - /** - * The hash code's value of the associated metric metric plug-in. - *
    - * After a new metric plug-in is registered as service in the OSGi - * framework, the PluginAdmin initializes this field with - * the service's ID value, by calling the setHashcode(String) - * method. - *
    - * Once the metric plug-in's install() method is called, - * the PluginAdmin replaces the old PluginInfo - * with a new one, whose hashcode field is initialized with - * the hash code's value, that this metric plug-in stored in its database - * record. - */ - private String hashcode; - - /** - * A list containing the current set of configuration parameters of the - * associated metric plug-in - */ - private Set config = - new HashSet(); - - /** - * This flag is set to false on a newly registered metric - * plug-ins, and changed to true after the metric plug-in's - * install() method is called (and successfully performed). - */ - public boolean installed = false; - - /** - * Empty constructor. - */ - public PluginInfo() { - - } - - /** - * Simple constructor, that creates a new PluginInfo instance - * and initializes it with the given metric plug-in's configuration - * parameters. - * - * @param c - the list of configuration parameters - */ - public PluginInfo(Set c) { - setPluginConfiguration(c); - } - - /** - * Creates a new PluginInfo instance, and initializes it with - * the given metric plug-in's configuration parameters and the description - * fields found in the given plug-in instance. - * - * @param c - the list of configuration parameters - * @param p the AlitheiaPlugin instance - */ - public PluginInfo(Set c, AlitheiaPlugin p) { - setPluginConfiguration(c); - if (p != null) { - setPluginName(p.getName()); - setPluginVersion(p.getVersion()); - setActivationTypes(p.getActivationTypes()); - } - } - - - /** - * Initializes the configuration set that is available for this plug-in. - * - * @param c the plug-in configuration set - */ - public void setPluginConfiguration (Set c) { - this.config = c; - } - - /** - * Returns the list of existing metric configuration parameters. - * - * @return The list of configuration parameters. - */ - public Set getConfiguration() { - return this.config; - } - - /** - * Returns the Id of the given configuration property. - * - * @param name the property's name - * @param type the property's type - * - * @return The property's Id, or null if the property does - * not exist. - */ - public Long getConfPropId (String name, String type) { - // Check if all values are valid - if ((name == null) || (type == null)) { - return null; - } - // Search for a matching property - for (PluginConfiguration property : config) { - if ((property.getName().equals(name)) - && (property.getType().equals(type))) { - return property.getId(); - } - } - return null; - } - - /** - * Verifies, if the specified configuration property exist in this - * plug-in's information object. - * - * @param name the property's name - * @param type the property's type - * - * @return true, if such property is found, - * or false otherwise. - */ - public boolean hasConfProp (String name, String type) { - return ((getConfPropId(name, type) == null) ? false : true); - } - - /** - * Sets a new value of existing metric plugin's configuration property - * by creating a new database record. - * - * @param db the DB components object - * @param name the configuration property's name - * @param newVal the new value, that should be assigned to the - * selected configuration property - * - * @return true upon successful update, of false - * when a corresponding database record does not exist. - * - * @throws Exception upon incorrect value's syntax, or - * invalid property's type. - */ - public boolean updateConfigEntry(DBService db, String name, String newVal) - throws Exception { - // Check for an invalid name - if (name == null) { - throw new Exception("Invalid name!"); - } - // Check if such configuration property exists - for (PluginConfiguration pc : config) { - if (pc.getName().equals(name)) { - // Retrieve the configuration property's type - ConfigurationType type = - ConfigurationType.fromString(pc.getType()); - // Check for invalid type - if (type == null) { - throw new Exception("Invalid property's type!"); - } - // Check for a boolean type - else if (type.equals(ConfigurationType.BOOLEAN)) { - if ((newVal.equals("true") == false) - && (newVal.equals("false") == false)) { - throw new Exception("Not a valid boolean value!"); - } - } - // Check for an integer type - else if (type.equals(ConfigurationType.INTEGER)) { - try { - Integer.valueOf(newVal); - } catch (NumberFormatException nfe) { - throw new Exception("Not a valid integer value!"); - } - } - - // Check for a double type - else if (type.equals(ConfigurationType.DOUBLE)) { - try { - Double.valueOf(newVal); - } catch (NumberFormatException nfe) { - throw new Exception("Not a valid double value!"); - } - } - - // Update the given configuration property - pc = db.attachObjectToDBSession(pc); - pc.setValue(newVal); - return true; - } - } - return false; - } - - /** - * Adds a new configuration property for this metric plug-in by creating - * a new database record for it. - * - * @param db the DB components object - * @param name the configuration property's name - * @param description the configuration property's description - * @param type the configuration property's type - * @param value the configuration property's value - * - * @return true upon successful append, of false - * when a corresponding database record can not be created. - * - * @throws Exception upon incorrect value's syntax, - * invalid property's type, or invalid property's name. - */ - public boolean addConfigEntry( - DBService db, - String name, - String description, - String type, - String value) - throws Exception { - // Check for an invalid name - if (name == null) { - throw new Exception("Invalid name!"); - } - - // Check for invalid type - if ((type == null) - || (ConfigurationType.fromString(type) == null)) { - throw new Exception("Invalid type!"); - } - - // Check for invalid value - if (value == null) { - throw new Exception("Invalid value!"); - } - // Check for invalid boolean value - else if (type.equals(ConfigurationType.BOOLEAN.toString())) { - if ((value.equals("true") == false) - && (value.equals("false") == false)) { - throw new Exception("Not a valid boolean value!"); - } - } - // Check for an invalid integer value - else if (type.equals(ConfigurationType.INTEGER.toString())) { - try { - Integer.valueOf(value); - } catch (NumberFormatException nfe) { - throw new Exception("Not a valid integer value!"); - } - } - - // Check for an invalid double value - else if (type.equals(ConfigurationType.DOUBLE.toString())) { - try { - Double.valueOf(value); - } catch (NumberFormatException nfe) { - throw new Exception("Not a valid double value!"); - } - } - - // Add the new configuration property - PluginConfiguration newParam = - new PluginConfiguration(); - newParam.setName(name); - newParam.setMsg((description != null) ? description : ""); - newParam.setType(type); - newParam.setValue(value); - Plugin p = Plugin.getPluginByHashcode(hashcode); - newParam.setPlugin(p); - return p.getConfigurations().add(newParam); -} + /** + * This enumeration includes all permitted types of configuration values, + * that a metrics can support. The various configuration parameters and + * their values are used mostly from internal metric processes, like results + * rendering and validation. + */ + public enum ConfigurationType { + INTEGER, STRING, BOOLEAN, DOUBLE; + + public static ConfigurationType fromString(String config) { + if (config.equals(BOOLEAN.toString())) + return BOOLEAN; + + if (config.equals(STRING.toString())) + return STRING; + + if (config.equals(INTEGER.toString())) + return INTEGER; + + if (config.equals(DOUBLE.toString())) + return DOUBLE; + + return null; + } + }; + + /** + * The service reference of the service that registered this metric plug-in + */ + private ServiceReference serviceRef = null; + + /** + * The name of the associated metric plug-in + */ + private String pluginName = null; + + /** + * The version of the associated metric plug-in + */ + private String pluginVersion = null; + + /** + * This list include all activation interfaces supported by the associated + * metric plug-in.
    + * The list of permitted activation interfaces is described in the + * {@link AlitheiaPlugin} interface and currently includes: + *
      + *
    • {@link StoredProjectMetric}
    • + *
    • {@link ProjectVersionMetric}
    • + *
    • {@link ProjectFileMetric}
    • + *
    • {@link FileGroupMetric}
    • + *
    + */ + Set> activationTypes = new HashSet>(); + + /** + * The hash code's value of the associated metric metric plug-in.
    + * After a new metric plug-in is registered as service in the OSGi + * framework, the PluginAdmin initializes this field with the + * service's ID value, by calling the setHashcode(String) + * method.
    + * Once the metric plug-in's install() method is called, the + * PluginAdmin replaces the old PluginInfo with a + * new one, whose hashcode field is initialized with the hash + * code's value, that this metric plug-in stored in its database record. + */ + private String hashcode; + + /** + * A list containing the current set of configuration parameters of the + * associated metric plug-in + */ + private Set config = new HashSet(); + + /** + * This flag is set to false on a newly registered metric + * plug-ins, and changed to true after the metric plug-in's + * install() method is called (and successfully performed). + */ + public boolean installed = false; + + /** + * Empty constructor. + */ + public PluginInfo() { - /** - * Removes an existing configuration property of this metric plug-in by - * deleting its database record. - * - * @param db the DB components object - * @param name the configuration property's name - * @param type the configuration property's type - * - * @return true upon successful remove, or false - * when a corresponding database record can not be found. - * - * @throws Exception upon invalid property's type or name. - */ - public boolean removeConfigEntry( - DBService db, - String name, - String type) - throws Exception { - // Check for an invalid name - if (name == null) { - throw new Exception("Invalid name!"); - } - - // Check for invalid type - if ((type == null) - || (ConfigurationType.fromString(type) == null)) { - throw new Exception("Invalid type!"); - } - - // Get the property's Id - Long propId = getConfPropId(name, type); - if (propId != null) { - // Remove the specified configuration property - PluginConfiguration prop = db.findObjectById( - PluginConfiguration.class, propId); - if ((prop != null) && (db.deleteRecord(prop))) { - return true; - } - } - - return false; -} + } + + /** + * Simple constructor, that creates a new PluginInfo instance + * and initializes it with the given metric plug-in's configuration + * parameters. + * + * @param c + * - the list of configuration parameters + */ + public PluginInfo(Set c) { + setPluginConfiguration(c); + } + + /** + * Creates a new PluginInfo instance, and initializes it with + * the given metric plug-in's configuration parameters and the description + * fields found in the given plug-in instance. + * + * @param c + * - the list of configuration parameters + * @param p + * the AlitheiaPlugin instance + */ + public PluginInfo(Set c, AlitheiaPlugin p) { + setPluginConfiguration(c); + if (p != null) { + setPluginName(p.getName()); + setPluginVersion(p.getVersion()); + setActivationTypes(p.getActivationTypes()); + } + } + + /** + * Initializes the configuration set that is available for this plug-in. + * + * @param c + * the plug-in configuration set + */ + public void setPluginConfiguration(Set c) { + this.config = c; + } + + /** + * Returns the list of existing metric configuration parameters. + * + * @return The list of configuration parameters. + */ + public Set getConfiguration() { + return this.config; + } + + /** + * Returns the Id of the given configuration property. + * + * @param name + * the property's name + * @param type + * the property's type + * + * @return The property's Id, or null if the property does not + * exist. + */ + public Long getConfPropId(String name, String type) { + // Check if all values are valid + if ((name == null) || (type == null)) { + return null; + } + // Search for a matching property + if (config != null) { + for (PluginConfiguration property : config) { + if ((property.getName().equals(name)) + && (property.getType().equals(type))) { + return property.getId(); + } + } + } + return null; + } + + /** + * Verifies, if the specified configuration property exist in this plug-in's + * information object. + * + * @param name + * the property's name + * @param type + * the property's type + * + * @return true, if such property is found, or + * false otherwise. + */ + public boolean hasConfProp(String name, String type) { + return ((getConfPropId(name, type) == null) ? false : true); + } + + /** + * Sets a new value of existing metric plugin's configuration property by + * creating a new database record. + * + * @param db + * the DB components object + * @param name + * the configuration property's name + * @param newVal + * the new value, that should be assigned to the selected + * configuration property + * + * @return true upon successful update, of false + * when a corresponding database record does not exist. + * + * @throws Exception upon incorrect value's syntax, or invalid + * property's type. + */ + public boolean updateConfigEntry(DBService db, String name, String newVal) + throws Exception { + // Check for an invalid name + if (name == null) { + throw new Exception("Invalid name!"); + } + // Check if such configuration property exists + for (PluginConfiguration pc : config) { + if (pc.getName().equals(name)) { + // Retrieve the configuration property's type + ConfigurationType type = ConfigurationType.fromString(pc + .getType()); + // Check for invalid type + if (type == null) { + throw new Exception("Invalid property's type!"); + } + // Check for a boolean type + else if (type.equals(ConfigurationType.BOOLEAN)) { + if ((newVal.equals("true") == false) + && (newVal.equals("false") == false)) { + throw new Exception("Not a valid boolean value!"); + } + } + // Check for an integer type + else if (type.equals(ConfigurationType.INTEGER)) { + try { + Integer.valueOf(newVal); + } catch (NumberFormatException nfe) { + throw new Exception("Not a valid integer value!"); + } + } + + // Check for a double type + else if (type.equals(ConfigurationType.DOUBLE)) { + try { + Double.valueOf(newVal); + } catch (NumberFormatException nfe) { + throw new Exception("Not a valid double value!"); + } + } + + // Update the given configuration property + pc = db.attachObjectToDBSession(pc); + pc.setValue(newVal); + return true; + } + } + return false; + } + + /** + * Adds a new configuration property for this metric plug-in by creating a + * new database record for it. + * + * @param db + * the DB components object + * @param name + * the configuration property's name + * @param description + * the configuration property's description + * @param type + * the configuration property's type + * @param value + * the configuration property's value + * + * @return true upon successful append, of false + * when a corresponding database record can not be created. + * + * @throws Exception upon incorrect value's syntax, invalid + * property's type, or invalid property's name. + */ + public boolean addConfigEntry(DBService db, String name, + String description, String type, String value) throws Exception { + // Check for an invalid name + if (name == null) { + throw new Exception("Invalid name!"); + } + + // Check for invalid type + if ((type == null) || (ConfigurationType.fromString(type) == null)) { + throw new Exception("Invalid type!"); + } + + // Check for invalid value + if (value == null) { + throw new Exception("Invalid value!"); + } + // Check for invalid boolean value + else if (type.equals(ConfigurationType.BOOLEAN.toString())) { + if ((value.equals("true") == false) + && (value.equals("false") == false)) { + throw new Exception("Not a valid boolean value!"); + } + } + // Check for an invalid integer value + else if (type.equals(ConfigurationType.INTEGER.toString())) { + try { + Integer.valueOf(value); + } catch (NumberFormatException nfe) { + throw new Exception("Not a valid integer value!"); + } + } + + // Check for an invalid double value + else if (type.equals(ConfigurationType.DOUBLE.toString())) { + try { + Double.valueOf(value); + } catch (NumberFormatException nfe) { + throw new Exception("Not a valid double value!"); + } + } + + // Add the new configuration property + PluginConfiguration newParam = new PluginConfiguration(); + newParam.setName(name); + newParam.setMsg((description != null) ? description : ""); + newParam.setType(type); + newParam.setValue(value); + Plugin p = Plugin.getPluginByHashcode(hashcode); + newParam.setPlugin(p); + return p.getConfigurations().add(newParam); + } + + /** + * Removes an existing configuration property of this metric plug-in by + * deleting its database record. + * + * @param db + * the DB components object + * @param name + * the configuration property's name + * @param type + * the configuration property's type + * + * @return true upon successful remove, or false + * when a corresponding database record can not be found. + * + * @throws Exception upon invalid property's type or name. + */ + public boolean removeConfigEntry(DBService db, String name, String type) + throws Exception { + // Check for an invalid name + if (name == null) { + throw new Exception("Invalid name!"); + } + + // Check for invalid type + if ((type == null) || (ConfigurationType.fromString(type) == null)) { + throw new Exception("Invalid type!"); + } + + // Get the property's Id + Long propId = getConfPropId(name, type); + if (propId != null) { + // Remove the specified configuration property + PluginConfiguration prop = db.findObjectById( + PluginConfiguration.class, propId); + if ((prop != null) && (db.deleteRecord(prop))) { + return true; + } + } + + return false; + } + + /** + * Sets the metric's name. In practice the metricName parameter + * must be equal with the name of the associated metric plug-in. + * + * @param metricName + * - the metric name + */ + public void setPluginName(String metricName) { + this.pluginName = metricName; + } + + /** + * Returns the metric name stored in this MetricInfo object. + * + * @return Metric name. + */ + public String getPluginName() { + return pluginName; + } - /** - * Sets the metric's name. In practice the metricName - * parameter must be equal with the name of the associated metric - * plug-in. - * - * @param metricName - the metric name - */ - public void setPluginName(String metricName) { - this.pluginName = metricName; - } - - /** - * Returns the metric name stored in this MetricInfo - * object. - * - * @return Metric name. - */ - public String getPluginName() { - return pluginName; - } - - /** - * Sets the metric's version. In practice the metricVersion - * parameter must be equal with the version of the associated metric - * plug-in. - * - * @param metricVersion - a metric version - */ - public void setPluginVersion(String metricVersion) { - this.pluginVersion = metricVersion; - } - - /** - * Returns the metric version stored in this MetricInfo - * object. - * - * @return Metric version. - */ - public String getPluginVersion() { - return pluginVersion; - } - - /** - * Sets the list of supported activation interfaces (types). In practice - * the given list must contain the same entries like those supported by - * the associated metric plug-in.
    - *
    - * Note: Any previous entries in this list will be deleted by this action. - * - * @param l - the list of supported activation interfaces - */ - public void setActivationTypes(Set> l) { - this.activationTypes = l; - } - - /** - * Returns the list off all activation interfaces (types) supported by the - * associated metric plug-in. - * - * @return - the list of supported activation interfaces - */ - public Set> getActivationTypes() { - return this.activationTypes; - } - - /** - * Adds one or more additional activation interfaces (types) to the - * locally stored list of supported activation interfaces. - * - * @param activator - the list of additional activation interfaces - */ - public void addActivationType(Class activator) { - this.activationTypes.add(activator); - } - - /** - * Compares the provided activation interface to the locally stored list - * of supported activation interfaces. - * - * @return true when the given activation interface is found - * in the list, or false otherwise. - */ - public boolean isActivationType(Class o) { - // Compare the activation list's entries to the given activation - // interface, until a match is found - Iterator> i = - this.activationTypes.iterator(); - while (i.hasNext()) { - if (i.next().equals(o)) - return true; - } - return false; - } - - /** - * Initializes the corresponding local field with the reference to the - * service, that registered the associated metric plug-in. - * - * @param serviceRef - the service reference - */ - public void setServiceRef(ServiceReference serviceRef) { - this.serviceRef = serviceRef; - } - - /** - * Returns the service reference that points to the associated metric - * plug-in. - * - * @return The service reference. - */ - public ServiceReference getServiceRef() { - return serviceRef; - } - - /** - * Sets the hash code's value of this MetricInfo instance. - *
    - * The value must be unique, which means that no other - * MetricInfo with the same hash code should be kept by - * the PluginAdmin instance that created this object. - * - * @param hashcode - the hash code's value of this object - */ - public void setHashcode(String hashcode) { - this.hashcode = hashcode; - } - - /** - * Returns the hash code's value of this MetricInfo instance. - * - * @return The hash code's value of this object. - */ - public String getHashcode() { - return hashcode; - } - - /** - * Creates a text representation of this MetricInfo - * instance. - * - * @return The text representation of this object. - */ - public String toString() { - StringBuilder b = new StringBuilder(); - // Add the metric plug-in's name - b.append(( - ((getPluginName() != null) - && (getPluginName().length() > 0)) - ? getPluginName() - : "[UNKNOWN]")); - // Add the metric plug-in's version - b.append(( - ((getPluginVersion() != null) - && (getPluginVersion().length() > 0)) - ? getPluginVersion() - : "[UNKNOWN]")); - // Add the metric plug-in's class name - b.append(" ["); - if (getServiceRef() != null) { - String[] classNames = - (String[]) serviceRef.getProperty(Constants.OBJECTCLASS); - b.append (( - ((classNames != null) - && (classNames.length > 0)) - ? (StringUtils.join(classNames, ",")) - : "UNKNOWN")); - } - else { - b.append("UNKNOWN"); - } - b.append("]"); - return b.toString(); - } + /** + * Returns the metric class stored in this MetricInfo object. + * + * @return Metric class. + */ + public String getPluginClass() { + return StringUtils.join((String[]) (this.getServiceRef() + .getProperty(Constants.OBJECTCLASS)), ","); + } + + /** + * Sets the metric's version. In practice the metricVersion + * parameter must be equal with the version of the associated metric + * plug-in. + * + * @param metricVersion + * - a metric version + */ + public void setPluginVersion(String metricVersion) { + this.pluginVersion = metricVersion; + } + + /** + * Returns the metric version stored in this MetricInfo object. + * + * @return Metric version. + */ + public String getPluginVersion() { + return pluginVersion; + } + + /** + * Sets the list of supported activation interfaces (types). In practice the + * given list must contain the same entries like those supported by the + * associated metric plug-in.
    + *
    + * Note: Any previous entries in this list will be deleted by this action. + * + * @param l + * - the list of supported activation interfaces + */ + public void setActivationTypes(Set> l) { + this.activationTypes = l; + } + + /** + * Returns the list off all activation interfaces (types) supported by the + * associated metric plug-in. + * + * @return - the list of supported activation interfaces + */ + public Set> getActivationTypes() { + return this.activationTypes; + } + + /** + * Adds one or more additional activation interfaces (types) to the locally + * stored list of supported activation interfaces. + * + * @param activator + * - the list of additional activation interfaces + */ + public void addActivationType(Class activator) { + this.activationTypes.add(activator); + } + + /** + * Compares the provided activation interface to the locally stored list of + * supported activation interfaces. + * + * @return true when the given activation interface is found in + * the list, or false otherwise. + */ + public boolean isActivationType(Class o) { + // Compare the activation list's entries to the given activation + // interface, until a match is found + Iterator> i = this.activationTypes.iterator(); + while (i.hasNext()) { + if (i.next().equals(o)) + return true; + } + return false; + } + + /** + * Initializes the corresponding local field with the reference to the + * service, that registered the associated metric plug-in. + * + * @param serviceRef + * - the service reference + */ + public void setServiceRef(ServiceReference serviceRef) { + this.serviceRef = serviceRef; + } + + /** + * Returns the service reference that points to the associated metric + * plug-in. + * + * @return The service reference. + */ + public ServiceReference getServiceRef() { + return serviceRef; + } + + /** + * Sets the hash code's value of this MetricInfo instance.
    + * The value must be unique, which means that no other + * MetricInfo with the same hash code should be kept by the + * PluginAdmin instance that created this object. + * + * @param hashcode + * - the hash code's value of this object + */ + public void setHashcode(String hashcode) { + this.hashcode = hashcode; + } + + /** + * Returns the hash code's value of this MetricInfo instance. + * + * @return The hash code's value of this object. + */ + public String getHashcode() { + return hashcode; + } + + /** + * Creates a text representation of this MetricInfo instance. + * + * @return The text representation of this object. + */ + public String toString() { + StringBuilder b = new StringBuilder(); + // Add the metric plug-in's name + b.append((((getPluginName() != null) && (getPluginName().length() > 0)) ? getPluginName() + : "[UNKNOWN]")); + // Add the metric plug-in's version + b.append((((getPluginVersion() != null) && (getPluginVersion().length() > 0)) ? getPluginVersion() + : "[UNKNOWN]")); + // Add the metric plug-in's class name + b.append(" ["); + if (getServiceRef() != null) { + String[] classNames = (String[]) serviceRef + .getProperty(Constants.OBJECTCLASS); + b.append((((classNames != null) && (classNames.length > 0)) ? (StringUtils + .join(classNames, ",")) : "UNKNOWN")); + } else { + b.append("UNKNOWN"); + } + b.append("]"); + return b.toString(); + } public int compareTo(PluginInfo pi) { return hashcode.compareTo(pi.hashcode); } + + public boolean isInstalled() { + return installed; + } } -//vi: ai nosi sw=4 ts=4 expandtab +// vi: ai nosi sw=4 ts=4 expandtab diff --git a/alitheia/core/src/main/java/eu/sqooss/service/scheduler/Job.java b/alitheia/core/src/main/java/eu/sqooss/service/scheduler/Job.java index 62e9745cc..2bbad159f 100644 --- a/alitheia/core/src/main/java/eu/sqooss/service/scheduler/Job.java +++ b/alitheia/core/src/main/java/eu/sqooss/service/scheduler/Job.java @@ -36,17 +36,12 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; -import java.util.List; import java.util.LinkedList; - -import java.lang.Comparable; -import java.lang.InterruptedException; +import java.util.List; import eu.sqooss.core.AlitheiaCore; -import eu.sqooss.service.util.Pair; - import eu.sqooss.service.db.DBService; -import eu.sqooss.service.scheduler.SchedulerException; +import eu.sqooss.service.util.Pair; /** * Abstract base class for all jobs running by the scheduler. @@ -55,524 +50,599 @@ */ public abstract class Job implements Comparable { - /** - * The state of the job. - * @author christoph - * - */ - public enum State { - Created, - Queued, - Running, - Finished, - Error, - Yielded - } - - /** - * This list contains the dependencies between the jobs. - * Each pair defines that the \a second one's execution depends on - * completion of the \a first one. - * - * As soon as the \a first job is finished, the pair is removed from - * the list. - */ - protected List> m_dependencies; - - /** - * List of jobs which depend on this job - */ - private List m_dependees; - - /** - * A list of objects that listen to this job's state changes - */ - private List listeners; - - private State m_state; - - private Scheduler m_scheduler; - - private Exception m_errorException; - - private WorkerThread m_worker; - - private int restarts = 0; - - private ResumePoint resumePoint; - - public void setWorkerThread(WorkerThread worker) { - m_worker = worker; - } - - public WorkerThread getWorkerThread() { - return m_worker; - } - - /** - * @return The current state of the job. - */ - public final State state() { - return m_state; - } - - /** - * Returns the Scheduler this Job was enqueued to. - */ - public Scheduler getScheduler() { - return m_scheduler; - } - - /** - * Adds a dependency. - * This job cannot be executed, as long \a other - * is not finished. - */ - public final synchronized void addDependency(Job other) throws SchedulerException { - // Dependencies of jobs can ony be changed before the job is queued. - // Otherwise, race conditions would occur in which it would be undefined - // if the dependency is applied or not. - if ( (state() != State.Created) && (state() != State.Yielded) ) { - throw new SchedulerException("Job dependencies cannot be added after the job has been queued."); - } - - // Don't allow circular dependencies - if( other.dependsOn(this) || (this==other) ) { - throw new SchedulerException("Job dependencies are not allowed to be cyclic."); - } - - if (m_dependencies == null) - m_dependencies = new LinkedList>(); - - synchronized (m_dependencies) { - Pair newDependency = new Pair(other, this); - m_dependencies.add(newDependency); - other.addDependee(this); - } - callDependenciesChanged(); - } - - /** - * Removes a dependency. - * \sa addDependency - */ - public final void removeDependency(Job other) { - if (m_dependencies == null) - return; - synchronized(m_dependencies) { - List> doomed = new LinkedList>(); - for (Pair p: m_dependencies ) { - if ( (p.first == other) && (p.second == this) ) { - doomed.add(p); - removeDependee(other); - } - } - m_dependencies.removeAll(doomed); - } - callDependenciesChanged(); - } - - /** - * Checks recursive whether this job depends on job \a other. - * @param other the job to check dependency of. - * @return true, when the job depends on \a other, otherwise false. - */ - public final boolean dependsOn(Job other) { - if (m_dependencies == null) - return false; - synchronized(m_dependencies) { - for (Pair p: m_dependencies ) { - if ( (p.first == other) && (p.second == this) ) { - return true; - } else if ( (p.second == this) && p.first.dependsOn(other)) { - return true; - } - } - return false; - } - } - - private final synchronized void addDependee(Job other) { - if (m_dependees == null) - m_dependees = new ArrayList(); - synchronized (m_dependees) { - m_dependees.add(other); - } - } - - private final synchronized void removeDependee(Job other) { - if (m_dependees == null) - return; - synchronized (m_dependees) { - m_dependees.remove(other); - } - } - - /** - * Executes the job. Makes sure that all dependencies are met. - * - * @return The time required to execute the Job in milliseconds. - * @throws Exception - */ - final public long execute() throws Exception { - DBService dbs = AlitheiaCore.getInstance().getDBService(); - long timer = System.currentTimeMillis(); - try { - setState(State.Running); - restart(); - - /*Idiot/bad programmer proofing*/ - assert (!dbs.isDBSessionActive()); - if (dbs.isDBSessionActive()) { - dbs.rollbackDBSession(); - setState(State.Error); //No uncommitted sessions are tolerated - } else { - if (state() != State.Yielded) - setState(State.Finished); - } - } catch(Exception e) { - - if (dbs.isDBSessionActive()) { - dbs.rollbackDBSession(); - } - - // In case of an exception, state becomes Error - m_errorException = e; - setState(State.Error); - // the Exception itself is forwarded - throw e; - } - return System.currentTimeMillis() - timer; - } - - /** - * Sets the job's state to Queued and informs the job about the new - * scheduler. - * This method should only be called by Scheduler.enqueue. - * @throws SchedulerException If the job is already enqueued. - */ - public final void callAboutToBeEnqueued(Scheduler s) throws SchedulerException { - if (m_scheduler != null) { - throw new SchedulerException("This job is already enqueued in a scheduler."); - } - aboutToBeEnqueued(s); - m_state = State.Queued; - m_scheduler = s; - } - - /** - * Sets the job's state back from Queued to Created and informs about being - * dequeud. - * This method should only be called by Scheduler.dequeue. - */ - public final void callAboutToBeDequeued(Scheduler s) { - aboutToBeDequeued(s); - - if (m_state == State.Queued) { - m_state = State.Created; - } - - m_scheduler = null; - } - - - /** - * The priority of the job is the order of job within the scheduler's queue. - * That leads to 0 being taking he highest precedence, then the higher numbers. - * It is not adviced to change the job's priority after it has been enqueued. That - * might lead to undefined behaviour. - * @return The priority of the job. - */ - abstract public long priority(); - - /** - * @return All unfinished jobs this job depends on. - */ - public final List dependencies() { - if (m_dependencies == null) - return Collections.EMPTY_LIST; - - List result = new LinkedList(); - synchronized (m_dependencies) { - for (Pair p: m_dependencies) { - if (p.second == this) { - result.add(p.first); - } - } - } - return result; - } - - /** - * Waits for the job to finish. - * Note that this method even returns when the job's state changes to Error. - */ - public final void waitForFinished() { - try { - synchronized (this) { - // if this method is running inside of a WorkerThread - // we try to pass the job we're waiting for to the thread. - if (Thread.currentThread() instanceof WorkerThread) { - WorkerThread t = (WorkerThread) Thread.currentThread(); - t.takeJob(this); - } else { - throw new Exception(); - } - } - } catch (Exception e) { - // if something went wrong with taking the job - // ok - we might be stuck... - if (m_scheduler.getSchedulerStats().getIdleWorkerThreads() == 0) { - m_scheduler.startOneShotWorkerThread(); - } - } - synchronized (this) { - while (state() != State.Finished) { - if (state() == State.Error) { - return; - } - try { - wait(); - } catch (InterruptedException e) { - } - } - } - } - - /** - * Checks, whether all dependencies are met and the job can be executed. - * @return true, when all dependencies are met. - */ - public boolean canExecute() { - final List deps = dependencies(); - Iterator it = deps.iterator(); - while (it.hasNext()) { - Job j = it.next(); - if (j.state() != State.Finished && j.state() != State.Error) { - return false; - } - } - return true; - } - - /** - * Return the exception that caused this Job to quit - * @return An exception object or null if the job has finished normally - */ - public final Exception getErrorException() { - return this.m_errorException; - } - - /** - * XXX bogus method, only used for putting it in into a Pair. - */ - public int compareTo(Job other) - { - return (this == other) ? 0 : 1; - } - - /** - * Protected default constructor. - */ - protected Job() { - m_scheduler = null; - m_errorException = null; - setState( State.Created ); - } - - /** - * Sets the job's state. - * @param s The new state. - */ - protected final void setState(State s) { - if (m_state == s) { - return; - } - - m_state = s; - - if ((m_state == State.Finished || m_state == State.Error) && m_dependencies != null) { - // remove the job from the dependency list - List unblockedJobs = new LinkedList(); - synchronized (m_dependencies) { - List> doomed = new LinkedList>(); - for (Pair p: m_dependencies) { - if (p.first == this) { - doomed.add(p); - unblockedJobs.add(p.second); - } - } - m_dependencies.removeAll(doomed); - } - /* tell all jobs depending on the now finished on to forward that - * to the scheduler - */ - for (Job j: unblockedJobs) { - j.callDependenciesChanged(); - } - } - - if ((m_state == State.Finished || m_state == State.Error) && m_dependees != null) { - synchronized (m_dependees) { - for (Job p: m_dependees) { - p.callDependenciesChanged(); - } - m_dependees.clear(); - } - } - - if (m_scheduler != null) { - m_scheduler.jobStateChanged(this, s); - } - - stateChanged(m_state); - fireStateChangedEvent(); - - synchronized(this) { - notifyAll(); - } - } - - /** - * Called, when the state of the job changed to \a state. - * The default implementation does nothing. - */ - protected void stateChanged(State state) { - - } - - /** - * If the job is queued to a scheduler, this methods tells the scheduler, - * that the job's dependencies have changed. - */ - protected final void callDependenciesChanged() { - if (m_scheduler != null) { - m_scheduler.jobDependenciesChanged(this); - } - } - - /** - * Restart a failing job by keeping count of the number of restarts - * @throws Exception to signify that the maximum number of restarts - * was reached - */ - protected void restart() throws Exception { - restarts++; - if (restarts >= 5) { - throw new Exception("Too many restarts - failing job"); - } - run(); - } - - /** - * Run the job. - * - * @throws Exception - * If thrown, the job ends up in Error state. - */ - abstract protected void run() throws Exception; - - /** - * Stop execution of the job until - * @param p - * @throws SchedulerException - */ - public void yield(ResumePoint p) throws SchedulerException { - synchronized (this) { - System.err.println(Thread.currentThread().getId() + ":" + toString() + ": State is :" + m_state); - if (m_state == State.Running) { - setState(State.Yielded); - this.resumePoint = p; - m_scheduler.yield(this, p); - } else { - throw new SchedulerException("Cannot yield non-running job: " - + this + " (state was:" + state() + ")"); - } - } - } - - public long resume() throws Exception { - long ts = System.currentTimeMillis(); - DBService dbs = AlitheiaCore.getInstance().getDBService(); - - if (state() != State.Yielded) - throw new SchedulerException("Cannot resume a non-yielded job"); - - if (resumePoint == null) - throw new SchedulerException("Resume point is null"); - - try { - setState(State.Running); - resumePoint.resume(); - - assert (!dbs.isDBSessionActive()); - if (dbs.isDBSessionActive()) { - dbs.rollbackDBSession(); - setState(State.Error); //No uncommitted sessions are tolerated - } else { - setState(State.Finished); - } - } catch(Exception e) { - - if (dbs.isDBSessionActive()) { - dbs.rollbackDBSession(); - } - - // In case of an exception, state becomes Error - m_errorException = e; - setState(State.Error); - // the Exception itself is forwarded - throw e; - } - - return System.currentTimeMillis() - ts; - } - - /** - * This method is called during queueing, right before the job is added to - * the work queue. - * The job is not in state Queued at this time. - * @param s The scheduler, the job has been enqueued to. - */ - protected void aboutToBeEnqueued(Scheduler s) { - } - - /** - * This method is called right before the job is dequeued without being - * executed. - * The job is still in it's previoues state. - * @parem s The scheduler, the job is dequeued from. - */ - protected void aboutToBeDequeued(Scheduler s) { - } - - /** - * Add a listener from the job's list of state listeners - */ - public final synchronized void addJobStateListener(JobStateListener l) { - if (listeners == null) - listeners = new ArrayList(); - listeners.add(l); - } - - /** - * Remove a listener from the job's list of state listeners - * @param l The listener to remove' - */ - public final synchronized void removeJobStateListener(JobStateListener l) { - if (listeners == null) - return; - listeners.remove(l); - } - - /** - * Called when the job's state has changed to notify clients about that. - */ - private void fireStateChangedEvent() { - if (listeners == null) - return; - for (JobStateListener l : listeners) { - l.jobStateChanged(this, m_state); - } - } + /** + * The state of the job. + * + * @author christoph + * + */ + public enum State { + Created, Queued, Running, Finished, Error, Yielded + } + + /** + * This list contains the dependencies between the jobs. Each pair defines + * that the \a second one's execution depends on completion of the \a first + * one. + * + * As soon as the \a first job is finished, the pair is removed from the + * list. + */ + protected List> m_dependencies; + + /** + * List of jobs which depend on this job + */ + private List m_dependees; + + /** + * A list of objects that listen to this job's state changes + */ + private List listeners; + + private State m_state; + + private Scheduler m_scheduler; + + private Exception m_errorException; + + private WorkerThread m_worker; + + private int restarts = 0; + + private ResumePoint resumePoint; + + public void setWorkerThread(WorkerThread worker) { + m_worker = worker; + } + + public WorkerThread getWorkerThread() { + return m_worker; + } + + /** + * @return The current state of the job. + */ + public final State state() { + return m_state; + } + + /** + * Returns the Scheduler this Job was enqueued to. + */ + public Scheduler getScheduler() { + return m_scheduler; + } + + /** + * Adds a dependency. This job cannot be executed, as long \a other is not + * finished. + */ + public final synchronized void addDependency(Job other) + throws SchedulerException { + // Dependencies of jobs can ony be changed before the job is queued. + // Otherwise, race conditions would occur in which it would be undefined + // if the dependency is applied or not. + if ((state() != State.Created) && (state() != State.Yielded)) { + throw new SchedulerException( + "Job dependencies cannot be added after the job has been queued."); + } + + // Don't allow circular dependencies + if (other.dependsOn(this) || (this == other)) { + throw new SchedulerException( + "Job dependencies are not allowed to be cyclic."); + } + + if (m_dependencies == null) + m_dependencies = new LinkedList>(); + + synchronized (m_dependencies) { + Pair newDependency = new Pair(other, this); + m_dependencies.add(newDependency); + other.addDependee(this); + } + callDependenciesChanged(); + } + + /** + * Removes a dependency. \sa addDependency + */ + public final void removeDependency(Job other) { + if (m_dependencies == null) + return; + synchronized (m_dependencies) { + List> doomed = new LinkedList>(); + for (Pair p : m_dependencies) { + if ((p.first == other) && (p.second == this)) { + doomed.add(p); + removeDependee(other); + } + } + m_dependencies.removeAll(doomed); + } + callDependenciesChanged(); + } + + /** + * Checks recursive whether this job depends on job \a other. + * + * @param other + * the job to check dependency of. + * @return true, when the job depends on \a other, otherwise false. + */ + public final boolean dependsOn(Job other) { + if (m_dependencies == null) + return false; + synchronized (m_dependencies) { + for (Pair p : m_dependencies) { + if ((p.first == other) && (p.second == this)) { + return true; + } else if ((p.second == this) && p.first.dependsOn(other)) { + return true; + } + } + return false; + } + } + + private final synchronized void addDependee(Job other) { + if (m_dependees == null) + m_dependees = new ArrayList(); + synchronized (m_dependees) { + m_dependees.add(other); + } + } + + private final synchronized void removeDependee(Job other) { + if (m_dependees == null) + return; + synchronized (m_dependees) { + m_dependees.remove(other); + } + } + + /** + * Executes the job. Makes sure that all dependencies are met. + * + * @return The time required to execute the Job in milliseconds. + * @throws Exception + */ + final public long execute() throws Exception { + DBService dbs = AlitheiaCore.getInstance().getDBService(); + long timer = System.currentTimeMillis(); + try { + setState(State.Running); + restart(); + + /* Idiot/bad programmer proofing */ + assert (!dbs.isDBSessionActive()); + if (dbs.isDBSessionActive()) { + dbs.rollbackDBSession(); + setState(State.Error); // No uncommitted sessions are tolerated + } else { + if (state() != State.Yielded) + setState(State.Finished); + } + } catch (Exception e) { + + if (dbs.isDBSessionActive()) { + dbs.rollbackDBSession(); + } + + // In case of an exception, state becomes Error + m_errorException = e; + setState(State.Error); + // the Exception itself is forwarded + throw e; + } + return System.currentTimeMillis() - timer; + } + + /** + * Sets the job's state to Queued and informs the job about the new + * scheduler. This method should only be called by Scheduler.enqueue. + * + * @throws SchedulerException + * If the job is already enqueued. + */ + public final void callAboutToBeEnqueued(Scheduler s) + throws SchedulerException { + if (m_scheduler != null) { + throw new SchedulerException( + "This job is already enqueued in a scheduler."); + } + aboutToBeEnqueued(s); + m_state = State.Queued; + m_scheduler = s; + } + + /** + * Sets the job's state back from Queued to Created and informs about being + * dequeud. This method should only be called by Scheduler.dequeue. + */ + public final void callAboutToBeDequeued(Scheduler s) { + aboutToBeDequeued(s); + + if (m_state == State.Queued) { + m_state = State.Created; + } + + m_scheduler = null; + } + + /** + * The priority of the job is the order of job within the scheduler's queue. + * That leads to 0 being taking he highest precedence, then the higher + * numbers. It is not adviced to change the job's priority after it has been + * enqueued. That might lead to undefined behaviour. + * + * @return The priority of the job. + */ + abstract public long priority(); + + /** + * @return All unfinished jobs this job depends on. + */ + public final List dependencies() { + if (m_dependencies == null) + return Collections.EMPTY_LIST; + + List result = new LinkedList(); + synchronized (m_dependencies) { + for (Pair p : m_dependencies) { + if (p.second == this) { + result.add(p.first); + } + } + } + return result; + } + + /** + * Waits for the job to finish. Note that this method even returns when the + * job's state changes to Error. + */ + public final void waitForFinished() { + try { + synchronized (this) { + // if this method is running inside of a WorkerThread + // we try to pass the job we're waiting for to the thread. + if (Thread.currentThread() instanceof WorkerThread) { + WorkerThread t = (WorkerThread) Thread.currentThread(); + t.takeJob(this); + } else { + throw new Exception(); + } + } + } catch (Exception e) { + // if something went wrong with taking the job + // ok - we might be stuck... + if (m_scheduler.getSchedulerStats().getIdleWorkerThreads() == 0) { + m_scheduler.startOneShotWorkerThread(); + } + } + synchronized (this) { + while (state() != State.Finished) { + if (state() == State.Error) { + return; + } + try { + wait(); + } catch (InterruptedException e) { + } + } + } + } + + /** + * Checks, whether all dependencies are met and the job can be executed. + * + * @return true, when all dependencies are met. + */ + public boolean canExecute() { + final List deps = dependencies(); + Iterator it = deps.iterator(); + while (it.hasNext()) { + Job j = it.next(); + if (j.state() != State.Finished && j.state() != State.Error) { + return false; + } + } + return true; + } + + /** + * Return the exception that caused this Job to quit + * + * @return An exception object or null if the job has finished normally + */ + public final Exception getErrorException() { + return this.m_errorException; + } + + /** + * XXX bogus method, only used for putting it in into a Pair. + */ + public int compareTo(Job other) { + return (this == other) ? 0 : 1; + } + + /** + * Protected default constructor. + */ + protected Job() { + m_scheduler = null; + m_errorException = null; + setState(State.Created); + } + + /** + * Sets the job's state. + * + * @param s + * The new state. + */ + protected final void setState(State s) { + if (m_state == s) { + return; + } + + m_state = s; + + if ((m_state == State.Finished || m_state == State.Error) + && m_dependencies != null) { + // remove the job from the dependency list + List unblockedJobs = new LinkedList(); + synchronized (m_dependencies) { + List> doomed = new LinkedList>(); + for (Pair p : m_dependencies) { + if (p.first == this) { + doomed.add(p); + unblockedJobs.add(p.second); + } + } + m_dependencies.removeAll(doomed); + } + /* + * tell all jobs depending on the now finished on to forward that to + * the scheduler + */ + for (Job j : unblockedJobs) { + j.callDependenciesChanged(); + } + } + + if ((m_state == State.Finished || m_state == State.Error) + && m_dependees != null) { + synchronized (m_dependees) { + for (Job p : m_dependees) { + p.callDependenciesChanged(); + } + m_dependees.clear(); + } + } + + if (m_scheduler != null) { + m_scheduler.jobStateChanged(this, s); + } + + stateChanged(m_state); + fireStateChangedEvent(); + + synchronized (this) { + notifyAll(); + } + } + + /** + * Called, when the state of the job changed to \a state. The default + * implementation does nothing. + */ + protected void stateChanged(State state) { + + } + + /** + * If the job is queued to a scheduler, this methods tells the scheduler, + * that the job's dependencies have changed. + */ + protected final void callDependenciesChanged() { + if (m_scheduler != null) { + m_scheduler.jobDependenciesChanged(this); + } + } + + /** + * Restart a failing job by keeping count of the number of restarts + * + * @throws Exception + * to signify that the maximum number of restarts was reached + */ + protected void restart() throws Exception { + restarts++; + if (restarts >= 5) { + throw new Exception("Too many restarts - failing job"); + } + run(); + } + + /** + * Run the job. + * + * @throws Exception + * If thrown, the job ends up in Error state. + */ + abstract protected void run() throws Exception; + + /** + * Stop execution of the job until + * + * @param p + * @throws SchedulerException + */ + public void yield(ResumePoint p) throws SchedulerException { + synchronized (this) { + System.err.println(Thread.currentThread().getId() + ":" + + toString() + ": State is :" + m_state); + if (m_state == State.Running) { + setState(State.Yielded); + this.resumePoint = p; + m_scheduler.yield(this, p); + } else { + throw new SchedulerException("Cannot yield non-running job: " + + this + " (state was:" + state() + ")"); + } + } + } + + public long resume() throws Exception { + long ts = System.currentTimeMillis(); + DBService dbs = AlitheiaCore.getInstance().getDBService(); + + if (state() != State.Yielded) + throw new SchedulerException("Cannot resume a non-yielded job"); + + if (resumePoint == null) + throw new SchedulerException("Resume point is null"); + + try { + setState(State.Running); + resumePoint.resume(); + + assert (!dbs.isDBSessionActive()); + if (dbs.isDBSessionActive()) { + dbs.rollbackDBSession(); + setState(State.Error); // No uncommitted sessions are tolerated + } else { + setState(State.Finished); + } + } catch (Exception e) { + + if (dbs.isDBSessionActive()) { + dbs.rollbackDBSession(); + } + + // In case of an exception, state becomes Error + m_errorException = e; + setState(State.Error); + // the Exception itself is forwarded + throw e; + } + + return System.currentTimeMillis() - ts; + } + + public String getJobType() { + if (this.getClass() != null) { // TODO How does this ever fail? remove + // if, and try/catch + try { + // result.append(j.getClass().getPackage().getName()); + // result.append(". " + j.getClass().getSimpleName()); + return this.toString(); + } catch (NullPointerException ex) { + return "NA"; + } + } else { + return "NA"; + } + } + + public String getExceptionType() { + Exception e = this.getErrorException(); + if (e != null) { + try { + StringBuilder result = new StringBuilder(""); + result.append(e.getClass().getPackage().getName()); + result.append(". " + e.getClass().getSimpleName()); + return result.toString(); + } catch (NullPointerException ex) { + return "NA"; + } + } else { + return "NA"; + } + } + + public String getExceptionText() { + Exception e = this.getErrorException(); + try { + return e.getMessage(); + } catch (NullPointerException ex) { + return "NA"; + } + } + + public String getExceptionBacktrace() { + Exception e = this.getErrorException(); + StringBuilder result = new StringBuilder(""); + if ((e != null) && (e.getStackTrace() != null)) { + for (StackTraceElement m : e.getStackTrace()) { + if (m == null) + continue; + result.append(m.getClassName()); + result.append(". "); + result.append(m.getMethodName()); + result.append("(), ("); + result.append(m.getFileName()); + result.append(":"); + result.append(m.getLineNumber()); + result.append(")
    "); + } + return result.toString(); + } else { + return "NA"; + } + } + + /** + * This method is called during queueing, right before the job is added to + * the work queue. The job is not in state Queued at this time. + * + * @param s + * The scheduler, the job has been enqueued to. + */ + protected void aboutToBeEnqueued(Scheduler s) { + } + + /** + * This method is called right before the job is dequeued without being + * executed. The job is still in it's previoues state. + * + * @parem s The scheduler, the job is dequeued from. + */ + protected void aboutToBeDequeued(Scheduler s) { + } + + /** + * Add a listener from the job's list of state listeners + */ + public final synchronized void addJobStateListener(JobStateListener l) { + if (listeners == null) + listeners = new ArrayList(); + listeners.add(l); + } + + /** + * Remove a listener from the job's list of state listeners + * + * @param l + * The listener to remove' + */ + public final synchronized void removeJobStateListener(JobStateListener l) { + if (listeners == null) + return; + listeners.remove(l); + } + + /** + * Called when the job's state has changed to notify clients about that. + */ + private void fireStateChangedEvent() { + if (listeners == null) + return; + for (JobStateListener l : listeners) { + l.jobStateChanged(this, m_state); + } + } } diff --git a/alitheia/core/src/main/java/eu/sqooss/service/tds/class_diagram_tds.png b/alitheia/core/src/main/java/eu/sqooss/service/tds/class_diagram_tds.png new file mode 100644 index 000000000..1004bdbf6 Binary files /dev/null and b/alitheia/core/src/main/java/eu/sqooss/service/tds/class_diagram_tds.png differ diff --git a/alitheia/core/src/main/java/eu/sqooss/service/tds/class_diagram_tds.ucls b/alitheia/core/src/main/java/eu/sqooss/service/tds/class_diagram_tds.ucls new file mode 100644 index 000000000..8cfe887dc --- /dev/null +++ b/alitheia/core/src/main/java/eu/sqooss/service/tds/class_diagram_tds.ucls @@ -0,0 +1,441 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/alitheia/core/src/main/java/package_diag_webadmin.gif b/alitheia/core/src/main/java/package_diag_webadmin.gif new file mode 100644 index 000000000..72b561371 Binary files /dev/null and b/alitheia/core/src/main/java/package_diag_webadmin.gif differ diff --git a/alitheia/core/src/main/java/package_diag_webadmin.ucls b/alitheia/core/src/main/java/package_diag_webadmin.ucls new file mode 100644 index 000000000..fd4446d59 --- /dev/null +++ b/alitheia/core/src/main/java/package_diag_webadmin.ucls @@ -0,0 +1,251 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/alitheia/core/src/main/java/package_diagram_core_no_impl_no_core.png b/alitheia/core/src/main/java/package_diagram_core_no_impl_no_core.png new file mode 100644 index 000000000..eac923357 Binary files /dev/null and b/alitheia/core/src/main/java/package_diagram_core_no_impl_no_core.png differ diff --git a/alitheia/core/src/main/java/package_diagram_core_no_impl_no_core.ucls b/alitheia/core/src/main/java/package_diagram_core_no_impl_no_core.ucls new file mode 100644 index 000000000..275a2ff98 --- /dev/null +++ b/alitheia/core/src/main/java/package_diagram_core_no_impl_no_core.ucls @@ -0,0 +1,396 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/alitheia/core/src/main/java/package_diagram_impl.ucls b/alitheia/core/src/main/java/package_diagram_impl.ucls new file mode 100644 index 000000000..43119782e --- /dev/null +++ b/alitheia/core/src/main/java/package_diagram_impl.ucls @@ -0,0 +1,10 @@ + + + + + + + + \ No newline at end of file diff --git a/alitheia/core/src/main/resources/alljobs.html b/alitheia/core/src/main/resources/alljobs.html deleted file mode 100644 index 4ffeea27f..000000000 --- a/alitheia/core/src/main/resources/alljobs.html +++ /dev/null @@ -1,13 +0,0 @@ -#set($section=4) -#parse("header.inc") -
    -#parse("menu.inc") - -
    -

    Failed Jobs (Last 1000)

    -
    - $admin.renderFailedJobs() -
    -
    -
    -#parse("sidebar.inc") diff --git a/alitheia/core/src/main/resources/index.html b/alitheia/core/src/main/resources/index.html index 8fd91055b..455f721f1 100644 --- a/alitheia/core/src/main/resources/index.html +++ b/alitheia/core/src/main/resources/index.html @@ -1,13 +1,16 @@ #set($section=1) #parse("header.inc") +$metrics.exec($request)
    #parse("menu.inc")

    $tr.label("plugins_mngm")

    - $metrics.render($request) + #parse("plugins_list.html")
    #parse("sidebar.inc") - +#set ($selectedPlugin = false) +#set ($requestAction = false) +#set ($errorMessages = false) diff --git a/alitheia/core/src/main/resources/job_fail_stats.html b/alitheia/core/src/main/resources/job_fail_stats.html new file mode 100644 index 000000000..5a13e58a4 --- /dev/null +++ b/alitheia/core/src/main/resources/job_fail_stats.html @@ -0,0 +1,24 @@ + + + + + + + + #set ($jobFailures = $jobs.getFailedJobStats()) + + #if ($jobFailures.size() == 0) + + + + + #else + #foreach ($key in $jobFailures.keySet()) + + + + + #end + #end + +
    Job TypeNum Jobs Failed
    No failures 
    $key$jobFailures.get($key)
    \ No newline at end of file diff --git a/alitheia/core/src/main/resources/job_run_stats.html b/alitheia/core/src/main/resources/job_run_stats.html new file mode 100644 index 000000000..9d80a75d6 --- /dev/null +++ b/alitheia/core/src/main/resources/job_run_stats.html @@ -0,0 +1,10 @@ +#set ($runningJobs = $jobs.getRunningJobs()) +#if ($runningJobs.size() == 0) + No running jobs +#else +
      + #foreach ($job in $runningJobs) +
    • $job
    • + #end +
    +#end \ No newline at end of file diff --git a/alitheia/core/src/main/resources/jobstat.html b/alitheia/core/src/main/resources/job_stat.html similarity index 95% rename from alitheia/core/src/main/resources/jobstat.html rename to alitheia/core/src/main/resources/job_stat.html index 05d1ea278..c8dc1dd7b 100644 --- a/alitheia/core/src/main/resources/jobstat.html +++ b/alitheia/core/src/main/resources/job_stat.html @@ -8,6 +8,6 @@ -#parse("jobstat.inc") +#parse("job_stat.inc") diff --git a/alitheia/core/src/main/resources/jobstat.inc b/alitheia/core/src/main/resources/job_stat.inc similarity index 54% rename from alitheia/core/src/main/resources/jobstat.inc rename to alitheia/core/src/main/resources/job_stat.inc index 4204e6bd9..e0e6322eb 100644 --- a/alitheia/core/src/main/resources/jobstat.inc +++ b/alitheia/core/src/main/resources/job_stat.inc @@ -1,22 +1,23 @@ +#set ($schedulerStats = $jobs.getSchedulerStats()) - + - + - + - + - + -
    $tr.label("executing") :$scheduler.RunningJobs$schedulerStats.getRunningJobs()
    $tr.label("waiting") :$scheduler.WaitingJobs$schedulerStats.getWaitingJobs()
    $tr.label("failed") :$scheduler.FailedJobs$schedulerStats.getFailedJobs()
    $tr.label("total") :$scheduler.TotalJobs$schedulerStats.getTotalJobs()
    $tr.label("workers") :$scheduler.WorkerThreads$schedulerStats.getWorkerThreads()
    + \ No newline at end of file diff --git a/alitheia/core/src/main/resources/job_wait_stats.html b/alitheia/core/src/main/resources/job_wait_stats.html new file mode 100644 index 000000000..495518e67 --- /dev/null +++ b/alitheia/core/src/main/resources/job_wait_stats.html @@ -0,0 +1,24 @@ + + + + + + + + #set ($jobWaiting = $jobs.getWaitingJobs()) + + #if ($jobWaiting.size() == 0) + + + + + #else + #foreach ($key in $jobWaiting.keySet()) + + + + + #end + #end + +
    Job TypeNum Jobs waiting
    No failures 
    $key$jobWaiting.get($key)
    \ No newline at end of file diff --git a/alitheia/core/src/main/resources/jobs.html b/alitheia/core/src/main/resources/jobs.html index 5ba790a4f..ae79bc13c 100644 --- a/alitheia/core/src/main/resources/jobs.html +++ b/alitheia/core/src/main/resources/jobs.html @@ -1,31 +1,32 @@ #set($section=4) +#set($schedulerStats = $jobs.getSchedulerStats()) #parse("header.inc")
    #parse("menu.inc")

    Job statistics

      -
    • Jobs Executing: $scheduler.RunningJobs
    • -
    • Jobs Waiting: $scheduler.WaitingJobs
    • -
    • Failed Jobs: $scheduler.FailedJobs
    • -
    • Worker Threads: $scheduler.WorkerThreads
    • -
    • Total Jobs: $scheduler.TotalJobs
    • +
    • Jobs Executing: $schedulerStats.getRunningJobs()
    • +
    • Jobs Waiting: $schedulerStats.getWaitingJobs()
    • +
    • Failed Jobs: $schedulerStats.getFailedJobs()
    • +
    • Worker Threads: $schedulerStats.getWorkerThreads()
    • +
    • Total Jobs: $schedulerStats.getTotalJobs()

    Running Jobs

    - $admin.renderJobRunStats() + #parse("job_run_stats.html")

    Waiting Jobs statistics

    - $admin.renderJobWaitStats() + #parse("job_wait_stats.html")

    Job failure statistics

    Details ...
    - $admin.renderJobFailStats() + #parse("job_fail_stats.html")
    diff --git a/alitheia/core/src/main/resources/jobs_all.html b/alitheia/core/src/main/resources/jobs_all.html new file mode 100644 index 000000000..d103c215b --- /dev/null +++ b/alitheia/core/src/main/resources/jobs_all.html @@ -0,0 +1,40 @@ +#set($section=4) +#parse("header.inc") +
    +#parse("menu.inc") +
    +

    Failed Jobs (Last 1000)

    +
    + + + + + + + + + + + #set ($failedJobs = $jobs.getFailedJobs()) + #if ($failedJobs) + #foreach ($job in $failedJobs) + #if ($job) + + + + + + + #end + #end + #else + + + + #end + +
    Job TypeException typeException textException backtrace
    $job.getJobType()$job.getExceptionType()$job.getExceptionText()$job.getExceptionBacktrace()
    No failed jobs.
    +
    +
    +
    +#parse("sidebar.inc") \ No newline at end of file diff --git a/alitheia/core/src/main/resources/logs.html b/alitheia/core/src/main/resources/logs.html index bcf08a9f2..e908fc832 100644 --- a/alitheia/core/src/main/resources/logs.html +++ b/alitheia/core/src/main/resources/logs.html @@ -3,9 +3,16 @@
    #parse("menu.inc")
    -

    Alitheia Logs

    -
      - $admin.renderLogs() +

      Alitheia Logs

      +
        +#set ($logList = $logs.getLogs()) +#if ($logList.size() == 0) +
      • <none>
      • +#else + #foreach ($log in $logList) +
      • $log
      • + #end +#end
    diff --git a/alitheia/core/src/main/resources/plugin_details.html b/alitheia/core/src/main/resources/plugin_details.html new file mode 100644 index 000000000..4593f4af9 --- /dev/null +++ b/alitheia/core/src/main/resources/plugin_details.html @@ -0,0 +1,131 @@ +
    + $selectedPlugin.getPluginName() + + + + + + + + + + + + + + + + + + + + +
    StatusNameClassVersion
    + #if ($selectedPlugin.isInstalled()) + Installed + #else + Registered + #end + $selectedPlugin.getPluginName()$selectedPlugin.getPluginClass()$selectedPlugin.getPluginVersion()
    + #if ($selectedPlugin.isInstalled()) + + + #else + + #end +
    + #if ($selectedPlugin.isInstalled()) +
    + Supported metrics + + + + + + + + + + + #if ($metrics.isPluginMetricsEmpty($selectedPlugin)) + + + + #else + #foreach ($metric in $metrics.getPluginMetrics($selectedPlugin)) + + + + + + + #end + #end + +
    IdNameTypeDescription
    + This plug-in does not support metrics. +
    $metric.getId()$metric.getMnemonic()$metric.getMetricType().getType()$metric.getDescription()
    +
    +
    + Configuration properties + + + + + + + + + + #if ($metrics.isPluginConfigurationEmpty($selectedPlugin)) + + + + #else + #foreach ($config in $metrics.getPluginConfiguration($selectedPlugin)) + + + + + + #end + #end + + + + +
    NameTypeValue
    This plug-in has no + configuration properties.
    + [Edit]  + $config.getName() + + $config.getType() + + $config.getValue() +
    +
    +
    + #end +
    \ No newline at end of file diff --git a/alitheia/core/src/main/resources/plugin_properties_create.html b/alitheia/core/src/main/resources/plugin_properties_create.html new file mode 100644 index 000000000..829043cfe --- /dev/null +++ b/alitheia/core/src/main/resources/plugin_properties_create.html @@ -0,0 +1,56 @@ +#set ($valPropName = $metrics.getValPropName()) +#set ($valPropType = $metrics.getValPropType()) +#set ($valPropDescr = $metrics.getValPropDescr()) +#set ($valPropValue = $metrics.getValPropValue()) +
    + Create property for $selectedPlugin.getPluginName() + + + + + + + + + + + + + + + + + + + + +
    + Name + + +
    + Description + + +
    + Type + + +
    + Value + + +
    + +   + +
    +
    \ No newline at end of file diff --git a/alitheia/core/src/main/resources/plugin_properties_update.html b/alitheia/core/src/main/resources/plugin_properties_update.html new file mode 100644 index 000000000..bec661078 --- /dev/null +++ b/alitheia/core/src/main/resources/plugin_properties_update.html @@ -0,0 +1,50 @@ +#set ($valPropName = $metrics.getValPropName()) +#set ($valPropType = $metrics.getValPropType()) +#set ($valPropDescr = $metrics.getValPropDescr()) +#set ($valPropValue = $metrics.getValPropValue()) +
    + Update property of $selectedPlugin.getPluginName() + + + + + + + + + + + + + + + + + + + + +
    + Name + + $valPropName +
    + Description + + $valPropDescr +
    + Type + + $valPropType +
    + Value + + +
    + +   + +   + +
    +
    \ No newline at end of file diff --git a/alitheia/core/src/main/resources/plugins_activators.html b/alitheia/core/src/main/resources/plugins_activators.html new file mode 100644 index 000000000..95086a0ab --- /dev/null +++ b/alitheia/core/src/main/resources/plugins_activators.html @@ -0,0 +1,13 @@ +#if($request.getParameter("showActivators") && $request.getParameter("showActivators") == "true") + #set($activators = $plugin.getActivationTypes()) + #if($activators) + #foreach($activator in $activators) + +   + + Activator: $activator.getName() + + + #end + #end +#end \ No newline at end of file diff --git a/alitheia/core/src/main/resources/plugins_all.html b/alitheia/core/src/main/resources/plugins_all.html new file mode 100644 index 000000000..b5d2d7b5d --- /dev/null +++ b/alitheia/core/src/main/resources/plugins_all.html @@ -0,0 +1,53 @@ +
    + All plug-ins + + + + + + + + + + + #foreach ($plugin in $metrics.getPluginsList()) + #if(!$plugin.isInstalled()) + + + + + + #parse("plugins_properties.html") + #parse("plugins_activators.html") + + #end + #end + #foreach ($plugin in $metrics.getPluginsList()) + #if($plugin.isInstalled()) + + + + + + #parse("plugins_properties.html") + #parse("plugins_activators.html") + + #end + #end + +
    StatusNameClassVersion
    [Edit] Registered$plugin.getPluginName()$plugin.getPluginClass()$plugin.getPluginVersion()
    [Edit] Installed$plugin.getPluginName()$plugin.getPluginClass()$plugin.getPluginVersion()
    + Display + properties Display + activators + +
    \ No newline at end of file diff --git a/alitheia/core/src/main/resources/plugins_list.html b/alitheia/core/src/main/resources/plugins_list.html new file mode 100644 index 000000000..7048d6182 --- /dev/null +++ b/alitheia/core/src/main/resources/plugins_list.html @@ -0,0 +1,43 @@ +#if($metrics.isDebugOn()) + $metrics.debugRequest($request) +#end +#if($metrics.isPluginsListEmpty()) +
    + All plug-ins + + No plug-ins found!  + + +
    +#else +
    + #set ($errorMessages = $metrics.getErrorMessages()) + #if ($errorMessages) +
    + Errors + $errorMessages +
    + #end + #set ($selectedPlugin = $metrics.getSelectedPlugin()) + #set ($requestAction = $request.getParameter("action")) + #if ($selectedPlugin && $selectedPlugin.isInstalled() && ($requestAction.equals("createProperty") || $requestAction.equals("updateProperty"))) + #if ($requestAction.equals("createProperty")) + #parse("plugin_properties_create.html") + #else + #parse("plugin_properties_update.html") + #end + #elseif($selectedPlugin) + #parse("plugin_details.html") + #else + #parse("plugins_all.html") + #end + + + + + + + + +
    +#end \ No newline at end of file diff --git a/alitheia/core/src/main/resources/plugins_properties.html b/alitheia/core/src/main/resources/plugins_properties.html new file mode 100644 index 000000000..a830b55de --- /dev/null +++ b/alitheia/core/src/main/resources/plugins_properties.html @@ -0,0 +1,15 @@ +#if($request.getParameter("showProperties") && $request.getParameter("showProperties") == "true") + #set($properties = $plugin.getConfiguration()) + #if($properties) + #foreach($property in $properties) + +   + + Property: $property.getName() +  Type: $property.getType() +  Value: $property.getValue() + + + #end + #end +#end \ No newline at end of file diff --git a/alitheia/core/src/main/resources/projects.html b/alitheia/core/src/main/resources/projects.html index 2da2f1a04..5e1b9a4a5 100644 --- a/alitheia/core/src/main/resources/projects.html +++ b/alitheia/core/src/main/resources/projects.html @@ -1,25 +1,31 @@ #set($section=3) +#set($selProject = $projects.getSelProject()) + #parse("header.inc")
    #parse("menu.inc")

    $tr.label("projects_mngm")

    +
    - $projects.render($request) + #if($request.getParameter("reqAction") == "conShowProject" && $selProject) + #parse("projects_show.html") + #elseif($request.getParameter("reqAction") == "reqAddProject") + #parse("projects_add.html") + #elseif($request.getParameter("reqAction") == "reqRemProject" && $selProject) + #parse("projects_delete.html") + #else + #parse("projects_list.html") + #end
    +

    $tr.label("install_new_project")

    project.properties file location
    -## Only print help if we're doing an addProject -- this is a complication -## because we use this one template for a gazillion different things. The -## extra clause before && is to handle null returns. -#if ($request.getParameter("reqAction") && ("reqAddProject" == $request.getParameter("reqAction"))) -

    $tr.label("help")

    - $tr.message("project_help") -#end +
    #parse("sidebar.inc") diff --git a/alitheia/core/src/main/resources/projects_add.html b/alitheia/core/src/main/resources/projects_add.html new file mode 100644 index 000000000..abf9c17da --- /dev/null +++ b/alitheia/core/src/main/resources/projects_add.html @@ -0,0 +1,66 @@ +
    + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Project name + + +
    + Contact e-mail + + +
    + Bug database + + +
    + Mailing list + + +
    + Source code + + +
    + ##apply button + + ## Cancel + +
    + #parse("projects_error_fieldset.html") + #parse("projects_hidden_fields.html") +

    $tr.label("help")

    + $tr.message("project_help") +
    + + + + + + + + + \ No newline at end of file diff --git a/alitheia/core/src/main/resources/projects_delete.html b/alitheia/core/src/main/resources/projects_delete.html new file mode 100644 index 000000000..ad29a1b78 --- /dev/null +++ b/alitheia/core/src/main/resources/projects_delete.html @@ -0,0 +1,26 @@ +#set($selProject = $projects.getSelProject()) + +
    +
    + + $tr.label("l0059"): $selProject.getName() + + + ## Confirmation message + + + ## Tool-bar + + +
    + $tr.message("delete_project") +
    + ##Confirm + + ## Cancel + +
    +
    + #parse("projects_error_fieldset.html") + #parse("projects_hidden_fields.html") +
    \ No newline at end of file diff --git a/alitheia/core/src/main/resources/projects_error_fieldset.html b/alitheia/core/src/main/resources/projects_error_fieldset.html new file mode 100644 index 000000000..24221f30e --- /dev/null +++ b/alitheia/core/src/main/resources/projects_error_fieldset.html @@ -0,0 +1,10 @@ +##display error messages +#set ($errors = $projects.getErrors()) +#if($errors.size() > 0) +
    + Errors +#foreach($error in $errors) + $error
    +#end +
    +#end \ No newline at end of file diff --git a/alitheia/core/src/main/resources/projects_hidden_fields.html b/alitheia/core/src/main/resources/projects_hidden_fields.html new file mode 100644 index 000000000..dcfc4dce0 --- /dev/null +++ b/alitheia/core/src/main/resources/projects_hidden_fields.html @@ -0,0 +1,12 @@ + ##addHiddenFields + ## "Action type" input field + + ## "Project Id" input field + #if($selProject) + + #else + + #end + ## "Plug-in hashcode" input field + + \ No newline at end of file diff --git a/alitheia/core/src/main/resources/projects_list.html b/alitheia/core/src/main/resources/projects_list.html new file mode 100644 index 000000000..8f5fa269b --- /dev/null +++ b/alitheia/core/src/main/resources/projects_list.html @@ -0,0 +1,129 @@ +#set ($projectsList = $projects.getProjects()) +#set($selProject = $projects.getSelProject()) +#if($selProject) + #set ($refreshURL = "/projects?projectId=$selProject.getId()") + #set ($selProjDisable = "") + #set ($selProjHidden = "") +#else + #set ($refreshURL = "/projects") + #set ($selProjDisable = 'disabled="disabled"') + #set ($selProjHidden = 'style="visibility: hidden"') +#end + +
    +
    + + + + + + + + + + + + + #if ($projectsList.size() == 0) + + + + + + #else + #foreach ($project in $projectsList) + #if ($selProject && $project.getId() == $selProject.getId()) + #set ($selVal = "") + #set ($selClass = "selected") + #else + #set ($selVal = $project.getId()) + #set ($selClass = "edit") + #end + + + + + + + + + + + + #end + #end + + + + + + + + + + + + + + + +
    $tr.label("l0066")$tr.label("l0067")$tr.label("l0068")$tr.label("l0069")$tr.label("l0070")$tr.label("l0071")$tr.label("l0073")
    + $tr.message("no_projects") +
    $project.getId() + #if($project.getId() == $request.getParameter("projectId")) + + #else + [Edit] + #end +   $project.getName() + + $projects.getLastProjectVersion($project) + + $projects.getLastEmailDate($project) + + $projects.getLastBug($project) + + $projects.getEvalState($project) + + $projects.getClusternode($project) +
    View + +
    Manage + + +
    Update + + + + + +
    +
    + #parse("projects_error_fieldset.html") + #parse("projects_hidden_fields.html") +
    diff --git a/alitheia/core/src/main/resources/projects_show.html b/alitheia/core/src/main/resources/projects_show.html new file mode 100644 index 000000000..fa775d7cc --- /dev/null +++ b/alitheia/core/src/main/resources/projects_show.html @@ -0,0 +1,66 @@ +#set($selProject = $projects.getSelProject()) +
    +
    + + Project information + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    + Project name + + $selProject.getName() +
    + Homepage + + $selProject.getWebsiteUrl() +
    + Contact e-mail + + $selProject.getContactUrl() +
    + Bug database + + $selProject.getBtsUrl() +
    + Mailing list + + $selProject.getMailUrl() +
    + Source code + + $selProject.getScmUrl() +
    + ##back button + +
    +
    + #parse("projects_error_fieldset.html") + #parse("projects_hidden_fields.html") +
    \ No newline at end of file diff --git a/alitheia/core/src/main/resources/projectslist.html b/alitheia/core/src/main/resources/projectslist.html index 8a05fe319..310349045 100644 --- a/alitheia/core/src/main/resources/projectslist.html +++ b/alitheia/core/src/main/resources/projectslist.html @@ -5,7 +5,7 @@

    $tr.label("projects_mngm")

    #set($projectlist = $projects.getProjects()) -#if($projectlist.size()<1) +#if($projectlist.size() < 1) $tr.label("no_projects_available") #else diff --git a/alitheia/core/src/main/resources/sidebar.inc b/alitheia/core/src/main/resources/sidebar.inc index da98331d0..30dd4d930 100644 --- a/alitheia/core/src/main/resources/sidebar.inc +++ b/alitheia/core/src/main/resources/sidebar.inc @@ -1,9 +1,10 @@ +#set ($schedulerStats = $jobs.getSchedulerStats())
    @@ -23,7 +24,7 @@
    $tr.label("job_info")
    diff --git a/alitheia/core/src/test/java/eu/sqooss/admin/test/AdminServiceImplTest.java b/alitheia/core/src/test/java/eu/sqooss/admin/test/AdminServiceImplTest.java index 9edc33bc6..eb044a7e3 100644 --- a/alitheia/core/src/test/java/eu/sqooss/admin/test/AdminServiceImplTest.java +++ b/alitheia/core/src/test/java/eu/sqooss/admin/test/AdminServiceImplTest.java @@ -14,100 +14,100 @@ import eu.sqooss.service.admin.actions.RunTimeInfo; public class AdminServiceImplTest { - - static AdminServiceImpl impl; - static long failid; - static long successid; - - @BeforeClass - public static void setUp() { - impl = new AdminServiceImpl(); - } - - @Test - public void testAdminServiceImpl() { - assertNotNull(impl); - } - - @Test - public void testRegisterAdminAction() { - RunTimeInfo rti = new RunTimeInfo(); - impl.registerAdminAction(rti.mnemonic(), RunTimeInfo.class); - assertEquals(1, impl.getAdminActions().size()); - - FailingAction fa = new FailingAction(); - impl.registerAdminAction(fa.mnemonic(), FailingAction.class); - assertEquals(2, impl.getAdminActions().size()); - - SucceedingAction su = new SucceedingAction(); - impl.registerAdminAction(su.mnemonic(), SucceedingAction.class); - assertEquals(3, impl.getAdminActions().size()); - } - - @Test - public void testGetAdminActions() { - Set actions = impl.getAdminActions(); - for (AdminAction aa : actions) - assertNotNull (aa); - } - - @Test - public void testCreate() { - AdminAction fail = impl.create("blah"); - assertNull(fail); - - fail = impl.create("fail"); - assertNotNull(fail); - ActionContainer ac = impl.liveactions().get(1L); - assertNotNull(ac); - assertEquals(-1, ac.end); - - assertEquals(AdminActionStatus.CREATED, fail.status()); - assertNull(fail.errors()); - assertNull(fail.results()); - failid = fail.id(); - } - - @Test - public void testExecute() { - AdminAction success = impl.create("win"); - assertNotNull(success); - impl.execute(success); - - assertNull(success.errors()); - assertEquals("#win", success.results().get("1")); - assertEquals(AdminActionStatus.FINISHED, success.status()); - successid = success.id(); - - AdminAction fail = impl.create("fail"); - assertNotNull(fail); - impl.execute(fail); - - assertNull(fail.results()); - assertEquals("#fail", fail.errors().get("1")); - assertEquals(AdminActionStatus.ERROR, fail.status()); - failid = fail.id(); - } - - @Test - public void testShow() { - AdminAction aa = impl.show(failid); - assertNotNull(aa); - - aa = impl.show(successid); - assertNotNull(aa); - } - - @Test - public void testGC() { - try { - Thread.sleep (300); - } catch (InterruptedException e) {} - int collected = impl.gc(1); - - assertEquals(collected, 2); - - AdminAction aa = impl.show(failid); - assertNull(aa); - } +// +// static AdminServiceImpl impl; +// static long failid; +// static long successid; +// +// @BeforeClass +// public static void setUp() { +// impl = new AdminServiceImpl(); +// } +// +// @Test +// public void testAdminServiceImpl() { +// assertNotNull(impl); +// } +// +// @Test +// public void testRegisterAdminAction() { +// RunTimeInfo rti = new RunTimeInfo(); +// impl.registerAdminAction(rti.mnemonic(), RunTimeInfo.class); +// assertEquals(1, impl.getAdminActions().size()); +// +// FailingAction fa = new FailingAction(); +// impl.registerAdminAction(fa.mnemonic(), FailingAction.class); +// assertEquals(2, impl.getAdminActions().size()); +// +// SucceedingAction su = new SucceedingAction(); +// impl.registerAdminAction(su.mnemonic(), SucceedingAction.class); +// assertEquals(3, impl.getAdminActions().size()); +// } +// +// @Test +// public void testGetAdminActions() { +// Set actions = impl.getAdminActions(); +// for (AdminAction aa : actions) +// assertNotNull (aa); +// } +// +// @Test +// public void testCreate() { +// AdminAction fail = impl.create("blah"); +// assertNull(fail); +// +// fail = impl.create("fail"); +// assertNotNull(fail); +// ActionContainer ac = impl.liveactions().get(1L); +// assertNotNull(ac); +// assertEquals(-1, ac.end); +// +// assertEquals(AdminActionStatus.CREATED, fail.status()); +// assertNull(fail.errors()); +// assertNull(fail.results()); +// failid = fail.id(); +// } +// +// @Test +// public void testExecute() { +// AdminAction success = impl.create("win"); +// assertNotNull(success); +// impl.execute(success); +// +// assertNull(success.errors()); +// assertEquals("#win", success.results().get("1")); +// assertEquals(AdminActionStatus.FINISHED, success.status()); +// successid = success.id(); +// +// AdminAction fail = impl.create("fail"); +// assertNotNull(fail); +// impl.execute(fail); +// +// assertNull(fail.results()); +// assertEquals("#fail", fail.errors().get("1")); +// assertEquals(AdminActionStatus.ERROR, fail.status()); +// failid = fail.id(); +// } +// +// @Test +// public void testShow() { +// AdminAction aa = impl.show(failid); +// assertNotNull(aa); +// +// aa = impl.show(successid); +// assertNotNull(aa); +// } +// +// @Test +// public void testGC() { +// try { +// Thread.sleep (300); +// } catch (InterruptedException e) {} +// int collected = impl.gc(1); +// +// assertEquals(collected, 2); +// +// AdminAction aa = impl.show(failid); +// assertNull(aa); +// } } diff --git a/alitheia/core/src/test/java/eu/sqooss/test/service/scheduler/JobTests.java b/alitheia/core/src/test/java/eu/sqooss/test/service/scheduler/JobTests.java new file mode 100644 index 000000000..e5c967370 --- /dev/null +++ b/alitheia/core/src/test/java/eu/sqooss/test/service/scheduler/JobTests.java @@ -0,0 +1,79 @@ +package eu.sqooss.test.service.scheduler; + +import java.lang.reflect.Field; + +import junit.framework.Assert; + +import org.junit.After; +import org.junit.BeforeClass; +import org.junit.Test; +import org.mockito.Mock; +import org.powermock.core.classloader.annotations.PrepareForTest; + +import eu.sqooss.service.scheduler.Job; + +@PrepareForTest(Job.class) +public class JobTests { + @Mock + protected static Job job; + + @BeforeClass + public static void setUp() { + job = new TestJob(10, "aaa"); + } + + @Test + public void testGetJobType() { + String type = "eu.sqooss.test.service.scheduler.TestJob"; + Assert.assertTrue(job.getJobType().startsWith(type)); + } + + @Test + public void testGetExceptionType() { + Assert.assertEquals("NA", job.getExceptionType()); + Exception e = new IllegalArgumentException("Exception text"); + setPrivateField("m_errorException", job, e); + Assert.assertEquals("java.lang. IllegalArgumentException", job.getExceptionType()); + } + + @Test + public void testGetExceptionText() { + Assert.assertEquals("NA", job.getExceptionText()); + Exception e = new IllegalArgumentException("Exception text"); + setPrivateField("m_errorException", job, e); + Assert.assertEquals("Exception text", job.getExceptionText()); + } + + @Test + public void testGetExceptionBacktrace() { + + Assert.assertEquals("NA", job.getExceptionBacktrace()); + Exception e = new IllegalArgumentException("Exception text"); + setPrivateField("m_errorException", job, e); + String backtrace = "eu.sqooss.test.service.scheduler.JobTests. testGetExceptionBacktrace(), (JobTests.java:80)
    sun.reflect.NativeMethodAccessorImpl. invoke0(), (NativeMethodAccessorImpl.java:-2)
    sun.reflect.NativeMethodAccessorImpl. invoke(), (NativeMethodAccessorImpl.java:57)
    sun.reflect.DelegatingMethodAccessorImpl. invoke(), (DelegatingMethodAccessorImpl.java:43)
    java.lang.reflect.Method. invoke(), (Method.java:606)
    org.junit.runners.model.FrameworkMethod$1. runReflectiveCall(), (FrameworkMethod.java:44)
    org.junit.internal.runners.model.ReflectiveCallable. run(), (ReflectiveCallable.java:15)
    org.junit.runners.model.FrameworkMethod. invokeExplosively(), (FrameworkMethod.java:41)
    org.junit.internal.runners.statements.InvokeMethod. evaluate(), (InvokeMethod.java:20)
    org.junit.internal.runners.statements.RunBefores. evaluate(), (RunBefores.java:28)
    org.junit.internal.runners.statements.RunAfters. evaluate(), (RunAfters.java:31)
    org.junit.runners.BlockJUnit4ClassRunner. runChild(), (BlockJUnit4ClassRunner.java:70)
    org.junit.runners.BlockJUnit4ClassRunner. runChild(), (BlockJUnit4ClassRunner.java:44)
    org.junit.runners.ParentRunner. runChildren(), (ParentRunner.java:180)
    org.junit.runners.ParentRunner. access$000(), (ParentRunner.java:41)
    org.junit.runners.ParentRunner$1. evaluate(), (ParentRunner.java:173)
    org.junit.internal.runners.statements.RunBefores. evaluate(), (RunBefores.java:28)
    org.junit.internal.runners.statements.RunAfters. evaluate(), (RunAfters.java:31)
    org.junit.runners.ParentRunner. run(), (ParentRunner.java:220)
    org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference. run(), (JUnit4TestReference.java:50)
    org.eclipse.jdt.internal.junit.runner.TestExecution. run(), (TestExecution.java:38)
    org.eclipse.jdt.internal.junit.runner.RemoteTestRunner. runTests(), (RemoteTestRunner.java:459)
    org.eclipse.jdt.internal.junit.runner.RemoteTestRunner. runTests(), (RemoteTestRunner.java:675)
    org.eclipse.jdt.internal.junit.runner.RemoteTestRunner. run(), (RemoteTestRunner.java:382)
    org.eclipse.jdt.internal.junit.runner.RemoteTestRunner. main(), (RemoteTestRunner.java:192)
    "; + Assert.assertEquals(backtrace, job.getExceptionBacktrace()); + } + + + @After + public void afterTest() { + setPrivateField("m_errorException", job, null); + } + + protected void setPrivateField(String field_name, Object object, Object value) { + Field field; + try { + field = Job.class.getDeclaredField(field_name); + field.setAccessible(true); + field.set(object, value); + } catch (NoSuchFieldException e1) { + e1.printStackTrace(); + } catch (SecurityException e1) { + e1.printStackTrace(); + } catch (IllegalArgumentException e1) { + e1.printStackTrace(); + } catch (IllegalAccessException e1) { + e1.printStackTrace(); + } + } +} diff --git a/alitheia/core/src/test/java/eu/sqooss/test/service/scheduler/TestJob.java b/alitheia/core/src/test/java/eu/sqooss/test/service/scheduler/TestJob.java index f9d8bc4fb..dd8dc216d 100644 --- a/alitheia/core/src/test/java/eu/sqooss/test/service/scheduler/TestJob.java +++ b/alitheia/core/src/test/java/eu/sqooss/test/service/scheduler/TestJob.java @@ -41,7 +41,7 @@ * * @author Christoph Schleifenbaum */ -class TestJob extends Job +public class TestJob extends Job { private int n; diff --git a/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/AbstractViewTest.java b/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/AbstractViewTest.java new file mode 100644 index 000000000..ed8b48a52 --- /dev/null +++ b/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/AbstractViewTest.java @@ -0,0 +1,392 @@ +package eu.sqooss.test.service.webadmin; + +import static org.junit.Assert.assertEquals; +import static org.mockito.BDDMockito.given; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.Date; +import java.util.Enumeration; +import java.util.Locale; +import java.util.ResourceBundle; +import java.util.StringTokenizer; + +import javax.servlet.http.HttpServletRequest; + +import junit.framework.Assert; + +import org.apache.velocity.VelocityContext; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.osgi.framework.BundleContext; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.reflect.Whitebox; + +import eu.sqooss.core.AlitheiaCore; +import eu.sqooss.impl.service.webadmin.AbstractView; +import eu.sqooss.service.cluster.ClusterNodeService; +import eu.sqooss.service.db.DBService; +import eu.sqooss.service.logging.LogManager; +import eu.sqooss.service.logging.Logger; +import eu.sqooss.service.metricactivator.MetricActivator; +import eu.sqooss.service.pa.PluginAdmin; +import eu.sqooss.service.scheduler.Scheduler; +import eu.sqooss.service.tds.TDSService; +import eu.sqooss.service.updater.UpdaterService; + +@RunWith(PowerMockRunner.class) +@PrepareForTest(AlitheiaCore.class) +public class AbstractViewTest { + + @Mock + BundleContext bc; + @Mock + VelocityContext vc; + AbstractView aw; + + @Test + public void testAbstractView() { + AlitheiaCore core = mock(AlitheiaCore.class); + LogManager lm = mock(LogManager.class); + DBService db = mock(DBService.class); + MetricActivator ma = mock(MetricActivator.class); + PluginAdmin pa = mock(PluginAdmin.class); + Scheduler s = mock(Scheduler.class); + TDSService tds = mock(TDSService.class); + UpdaterService us = mock(UpdaterService.class); + ClusterNodeService cn = mock(ClusterNodeService.class); + SecurityManager sm = mock(SecurityManager.class); + Logger logger = mock(Logger.class); + + when(core.getLogManager()).thenReturn(null, lm); + when(lm.createLogger(anyString())).thenReturn(logger); + + reinitAbstractView(); + + Field field; + try { + field = getField("sobjCore"); + + // test with no AlitheiaCore initialization + Assert.assertNull(field.get(aw)); + + PowerMockito.mockStatic(AlitheiaCore.class); + given(AlitheiaCore.getInstance()).willReturn(core); + + // test AlitheiaCore initialization + reinitAbstractView(); + Assert.assertEquals(core, field.get(aw)); + + when(core.getDBService()).thenReturn(db, null); + when(core.getPluginAdmin()).thenReturn(pa, null); + when(core.getScheduler()).thenReturn(s, null); + when(core.getMetricActivator()).thenReturn(ma, null); + when(core.getTDSService()).thenReturn(tds, null); + when(core.getUpdater()).thenReturn(us, null); + when(core.getClusterNodeService()).thenReturn(null, cn); + when(core.getMetricActivator()).thenReturn(ma, null); + when(core.getSecurityManager()).thenReturn(sm, null); + doNothing().when(logger).debug(anyString()); + + // test Logger manager and logger + reinitAbstractView(); + field = getField("sobjLogManager"); + Assert.assertEquals(lm, field.get(aw)); + field = getField("sobjLogger"); + Assert.assertEquals(logger, field.get(aw)); + + // test all the other fields + field = getField("sobjDB"); + Assert.assertEquals(db, field.get(aw)); + field = getField("sobjPA"); + Assert.assertEquals(pa, field.get(aw)); + field = getField("sobjSched"); + Assert.assertEquals(s, field.get(aw)); + field = getField("compMA"); + Assert.assertEquals(ma, field.get(aw)); + field = getField("sobjTDS"); + Assert.assertEquals(tds, field.get(aw)); + field = getField("sobjUpdater"); + Assert.assertEquals(us, field.get(aw)); + field = getField("sobjSecurity"); + Assert.assertEquals(sm, field.get(aw)); + + reinitAbstractView(); + field = getField("sobjClusterNode"); + Assert.assertEquals(cn, field.get(aw)); + verify(logger, times(8)).debug(anyString()); + + } catch (IllegalArgumentException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + + @Test + public void testResourceGetters() { + Assert.assertEquals("message", AbstractView.getMsg("message")); + Assert.assertEquals("message", AbstractView.getErr("message")); + Assert.assertEquals("message", AbstractView.getLbl("message")); + } + + @Test + public void testGetMsg() { + AbstractView.initResources(Locale.ENGLISH); + Assert.assertEquals("another message", + AbstractView.getMsg("another message")); + Assert.assertEquals("Check log for details.", + AbstractView.getMsg("m0001")); + Assert.assertEquals("Undefined parameter name!", + AbstractView.getMsg(null)); + } + + @Test + public void testGetErr() { + AbstractView.initResources(Locale.ENGLISH); + Assert.assertEquals("another message", + AbstractView.getErr("another message")); + Assert.assertEquals("Can not add this user to the selected group!", + AbstractView.getErr("e0001")); + Assert.assertEquals("Undefined parameter name!", + AbstractView.getErr(null)); + } + + @Test + public void testGetLbl() { + AbstractView.initResources(Locale.ENGLISH); + Assert.assertEquals("another message", + AbstractView.getLbl("another message")); + Assert.assertEquals("Alitheia", AbstractView.getLbl("l0001")); + Assert.assertEquals("Undefined parameter name!", + AbstractView.getLbl(null)); + } + + @Test + public void testGetMessagesBundle() { + Assert.assertEquals( + ResourceBundle.getBundle("ResourceMessages", Locale.ENGLISH), + AbstractView.getMessagesBundle(Locale.ENGLISH)); + Assert.assertEquals( + ResourceBundle.getBundle("ResourceMessages", Locale.ENGLISH), + AbstractView.getMessagesBundle(Locale.GERMAN)); + Assert.assertNotSame( + ResourceBundle.getBundle("ResourceErrors", Locale.ENGLISH), + AbstractView.getMessagesBundle(Locale.ENGLISH)); + } + + @Test + public void testGetErrorsBundle() { + Assert.assertEquals( + ResourceBundle.getBundle("ResourceErrors", Locale.ENGLISH), + AbstractView.getErrorsBundle(Locale.ENGLISH)); + Assert.assertEquals( + ResourceBundle.getBundle("ResourceErrors", Locale.ENGLISH), + AbstractView.getErrorsBundle(Locale.GERMAN)); + Assert.assertNotSame( + ResourceBundle.getBundle("ResourceMessages", Locale.ENGLISH), + AbstractView.getErrorsBundle(Locale.ENGLISH)); + } + + @Test + public void testGetLabelsBundle() { + Assert.assertEquals( + ResourceBundle.getBundle("ResourceLabels", Locale.ENGLISH), + AbstractView.getLabelsBundle(Locale.ENGLISH)); + Assert.assertEquals( + ResourceBundle.getBundle("ResourceLabels", Locale.ENGLISH), + AbstractView.getLabelsBundle(Locale.GERMAN)); + Assert.assertNotSame( + ResourceBundle.getBundle("ResourceMessages", Locale.ENGLISH), + AbstractView.getLabelsBundle(Locale.ENGLISH)); + } + + @Test + public void testDebugRequest() { + Method method = getMethod("debugRequest", HttpServletRequest.class); + HttpServletRequest request = mock(HttpServletRequest.class); + Enumeration e = new StringTokenizer("name1 name2 name3"); + String expected = "name1=null
    \nname2=null
    \nname3=null
    \n"; + when(request.getParameterNames()).thenReturn(e); + try { + Assert.assertEquals(expected, method.invoke(aw, request)); + } catch (IllegalAccessException e1) { + e1.printStackTrace(); + } catch (IllegalArgumentException e1) { + e1.printStackTrace(); + } catch (InvocationTargetException e1) { + e1.printStackTrace(); + } + } + + @Test + public void testFromString() { + Method method = getMethod("fromString", String.class); + try { + Assert.assertEquals(null, method.invoke(aw, "zbla")); + Assert.assertEquals((long)1349504334, method.invoke(aw, "1349504334")); + Assert.assertEquals((long)-1349504334, method.invoke(aw, "-1349504334")); + } catch (IllegalAccessException e1) { + e1.printStackTrace(); + } catch (IllegalArgumentException e1) { + e1.printStackTrace(); + } catch (InvocationTargetException e1) { + e1.printStackTrace(); + } + } + + @Test + public void testCheckName() { + Method method = getMethod("checkName", String.class); + try { + String text = null; + Assert.assertFalse((boolean)method.invoke(aw, text)); + Assert.assertFalse((boolean)method.invoke(aw, " aaa")); + Assert.assertFalse((boolean)method.invoke(aw, "aaa ")); + Assert.assertTrue((boolean)method.invoke(aw, "alphabet")); + Assert.assertTrue((boolean)method.invoke(aw, "123")); + Assert.assertTrue((boolean)method.invoke(aw, "alphanumeric123")); + Assert.assertTrue((boolean)method.invoke(aw, "alphanum eric123")); + } catch (IllegalAccessException e1) { + e1.printStackTrace(); + } catch (IllegalArgumentException e1) { + e1.printStackTrace(); + } catch (InvocationTargetException e1) { + e1.printStackTrace(); + } + } + + @Test + public void testCheckProjectName() { + Method method = getMethod("checkProjectName", String.class); + try { + String text = null; + Assert.assertFalse((boolean)method.invoke(aw, text)); + Assert.assertFalse((boolean)method.invoke(aw, " aaa")); + Assert.assertFalse((boolean)method.invoke(aw, "aaa ")); + Assert.assertFalse((boolean)method.invoke(aw, "_aaa")); + Assert.assertFalse((boolean)method.invoke(aw, "aaa_")); + Assert.assertFalse((boolean)method.invoke(aw, "-aaa")); + Assert.assertFalse((boolean)method.invoke(aw, "aaa-")); + Assert.assertTrue((boolean)method.invoke(aw, "alphabet")); + Assert.assertTrue((boolean)method.invoke(aw, "123")); + Assert.assertTrue((boolean)method.invoke(aw, "alphanumeric123")); + Assert.assertTrue((boolean)method.invoke(aw, "alphanum eric123")); + Assert.assertTrue((boolean)method.invoke(aw, "alphanum-eric123")); + Assert.assertTrue((boolean)method.invoke(aw, "alphanum_eric123")); + } catch (IllegalAccessException e1) { + e1.printStackTrace(); + } catch (IllegalArgumentException e1) { + e1.printStackTrace(); + } catch (InvocationTargetException e1) { + e1.printStackTrace(); + } + } + + @Test + public void testCheckEmail() { + Method method = getMethod("checkEmail", String.class); + try { + String text = null; + Assert.assertFalse((boolean)method.invoke(aw, text)); + Assert.assertFalse((boolean)method.invoke(aw, "aaa..aaa")); + Assert.assertFalse((boolean)method.invoke(aw, "aaa@aa@a")); + Assert.assertFalse((boolean)method.invoke(aw, ".aaa@aaa")); + Assert.assertFalse((boolean)method.invoke(aw, "aaa@.aaa")); + Assert.assertFalse((boolean)method.invoke(aw, "aaa.@aaa")); + Assert.assertFalse((boolean)method.invoke(aw, "aaa@aaa.")); + Assert.assertTrue((boolean)method.invoke(aw, "email@example.com")); + Assert.assertTrue((boolean)method.invoke(aw, "_______@example.com")); + Assert.assertTrue((boolean)method.invoke(aw, "1234567890@example.com")); + Assert.assertFalse((boolean)method.invoke(aw, "Joe Smith ")); + Assert.assertFalse((boolean)method.invoke(aw, "email@example")); + } catch (IllegalAccessException e1) { + e1.printStackTrace(); + } catch (IllegalArgumentException e1) { + e1.printStackTrace(); + } catch (InvocationTargetException e1) { + e1.printStackTrace(); + } + } + + @Test + public void testCheckTDSUrl() { + Method method = getMethod("checkTDSUrl", String.class); + TDSService tds = mock(TDSService.class); + when(tds.isURLSupported(anyString())).thenReturn(true); + try { + Assert.assertTrue((boolean)method.invoke(aw, "url")); + verify(tds, times(1)).isURLSupported(anyString()); + } catch (IllegalAccessException e1) { + e1.printStackTrace(); + } catch (IllegalArgumentException e1) { + e1.printStackTrace(); + } catch (InvocationTargetException e1) { + e1.printStackTrace(); + } + } + + @Test + public void testGetUptime() { + String uptimeTruth = "25:02:03:02"; + + long days = 25L * 24L * 60L * 60L * 1000L; + long hours = 2L * 60L * 60L * 1000L; + long minutes = 2L * 60L * 1000L; + long seconds = 62L * 1000L; + long dateEntry = new Date().getTime() - days - hours - minutes + - seconds; + + Whitebox.setInternalState(AbstractView.class, dateEntry); + String uptime = AbstractView.getUptime(); + assertEquals(uptimeTruth, uptime); + } + + protected void reinitAbstractView() { + aw = new AbstractView(bc, vc) { + + @Override + public void exec(HttpServletRequest req) { + // TODO Auto-generated method stub + + } + }; + } + + protected Field getField(String name) { + Field field = null; + try { + field = AbstractView.class.getDeclaredField(name); + field.setAccessible(true); + } catch (NoSuchFieldException e) { + e.printStackTrace(); + } catch (SecurityException e) { + e.printStackTrace(); + } + return field; + } + + protected Method getMethod(String name, Class... parameterTypes) { + Method method = null; + try { + method = AbstractView.class.getDeclaredMethod(name, parameterTypes); + method.setAccessible(true); + } catch (NoSuchMethodException e) { + e.printStackTrace(); + } catch (SecurityException e) { + e.printStackTrace(); + } + return method; + } + +} diff --git a/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/AdminServletTest.java b/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/AdminServletTest.java new file mode 100644 index 000000000..ff2377275 --- /dev/null +++ b/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/AdminServletTest.java @@ -0,0 +1,232 @@ +package eu.sqooss.test.service.webadmin; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.powermock.api.mockito.PowerMockito.mockStatic; + +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Hashtable; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.app.VelocityEngine; +import org.apache.velocity.exception.ParseErrorException; +import org.apache.velocity.exception.ResourceNotFoundException; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.osgi.framework.BundleContext; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.reflect.Whitebox; + +import eu.sqooss.core.AlitheiaCore; +import eu.sqooss.impl.service.webadmin.AbstractView; +import eu.sqooss.impl.service.webadmin.AdminServlet; +import eu.sqooss.service.admin.AdminAction; +import eu.sqooss.service.admin.AdminService; +import eu.sqooss.service.db.DBService; +import eu.sqooss.service.logging.Logger; +import eu.sqooss.service.scheduler.Scheduler; +import eu.sqooss.service.scheduler.SchedulerStats; +import eu.sqooss.service.util.Pair; +import eu.sqooss.service.webadmin.WebadminService; + + +@RunWith(PowerMockRunner.class) +@PrepareForTest({AlitheiaCore.class}) +public class AdminServletTest { + + @Mock private BundleContext bc; + @Mock private WebadminService webadmin; + @Mock private Logger logger; + @Mock private VelocityEngine ve; + @Mock private AlitheiaCore core; + @Mock private DBService dbs; + @Mock private AdminService as; + @Mock private AdminAction aa; + @Mock private Scheduler scheduler; + @Mock private VelocityContext vc; + @Mock private HttpServletRequest request; + @Mock private HttpServletResponse response; + @Mock private Template template; + @Mock private PrintWriter writer; + @Mock private ServletOutputStream ostream; + + private AdminServlet servlet; + + private void initServlet() { + mockStatic(AlitheiaCore.class); + + when(AlitheiaCore.getInstance()).thenReturn(core); + when(core.getDBService()).thenReturn(dbs); + when(core.getAdminService()).thenReturn(as); + when(as.create(any(String.class))).thenReturn(aa); + + servlet = new AdminServlet(bc, webadmin, logger, ve); + + Whitebox.setInternalState(servlet, vc); + + Whitebox.setInternalState(AbstractView.class, scheduler); + when(scheduler.getSchedulerStats()).thenReturn(new SchedulerStats()); + } + + + @Test + public void testConstructor() { + initServlet(); + assertNotNull(servlet); + + Hashtable> dynContent = + Whitebox.getInternalState(servlet, "dynamicContentMap"); + Hashtable> statContent = + Whitebox.getInternalState(servlet, "staticContentMap"); + + assertEquals(14, dynContent.size()); + assertEquals(15, statContent.size()); + } + + @Test + public void testCreateSubstitutions() throws Exception { + initServlet(); + + Whitebox.invokeMethod(servlet, "createSubstitutions", request); + + verify(vc, times(4)).put(any(String.class), any(Object.class)); + } + + @Test + public void testSendPageException() throws Exception { + initServlet(); + + String path = ""; + when(ve.getTemplate(any(String.class))).thenThrow(new IllegalArgumentException()); + Whitebox.invokeMethod(servlet, "sendPage", response, request, path); + + //verify that response status is set correctly + verify(response, times(1)).setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); + } + + + @Test + public void testSendPage() throws ResourceNotFoundException, ParseErrorException, Exception { + initServlet(); + + String path = ""; + + when(ve.getTemplate(any(String.class))).thenReturn(template); + when(response.getWriter()).thenReturn(writer); + + Whitebox.invokeMethod(servlet, "sendPage", response, request, path); + + //Verify that merge was called on template + verify(template, times(1)).merge(any(VelocityContext.class), any(PrintWriter.class)); + //verify that print was called on writer + verify(writer, times(1)).print(any(String.class)); + + } + + @Test + public void testSendResource() throws Exception { + initServlet(); + when(response.getOutputStream()).thenReturn(ostream); + + String sourceFile = "/sqo-oss.png"; + String contentType = "image/x-png"; + + Pair source = new Pair(sourceFile, contentType); + + Whitebox.invokeMethod(servlet, "sendResource", response, source); + + //verify that whole image was been sent + verify(ostream, times(6)).write(any(byte[].class), any(int.class), any(int.class)); + } + + + @Test(expected=IOException.class) + public void testSendResourceNotFound() throws Exception { + initServlet(); + when(response.getOutputStream()).thenReturn(ostream); + + String sourceFile = "Non existing file"; + String contentType = ""; + + Pair source = new Pair(sourceFile, contentType); + + Whitebox.invokeMethod(servlet, "sendResource", response, source); + } + + @Test + public void testDoPost() throws Exception { + initServlet(); + + when(request.getPathInfo()).thenReturn("Non existing path"); + Whitebox.invokeMethod(servlet, "doPost", request, response); + + //verify that response status is set correctly + verify(dbs, times(2)).isDBSessionActive(); + } + + + @Test + public void testDoGet() throws Exception { + initServlet(); + + when(request.getPathInfo()).thenReturn("Non existing path"); + Whitebox.invokeMethod(servlet, "doGet", request, response); + + //verify that response status is set correctly + verify(dbs, times(2)).isDBSessionActive(); + } + + @Test + public void testHandleRequestNonExistingPath() throws Exception { + initServlet(); + + when(request.getPathInfo()).thenReturn("Non existing path"); + Whitebox.invokeMethod(servlet, "handleRequest", request, response); + + //verify that response status is set correctly + verify(dbs, times(2)).isDBSessionActive(); + } + + @Test + public void testHandleRequestDynamic() throws Exception { + initServlet(); + + when(request.getPathInfo()).thenReturn("/jobs"); + when(ve.getTemplate(any(String.class))).thenReturn(template); + when(response.getWriter()).thenReturn(writer); + + Whitebox.invokeMethod(servlet, "handleRequest", request, response); + + //Verify that merge was called on template + verify(template, times(1)).merge(any(VelocityContext.class), any(PrintWriter.class)); + //verify that print was called on writer + verify(writer, times(1)).print(any(String.class)); + } + + @Test + public void testHandleRequestStatic() throws Exception { + initServlet(); + + when(request.getPathInfo()).thenReturn("/sqo-oss.png"); + when(response.getOutputStream()).thenReturn(ostream); + + Whitebox.invokeMethod(servlet, "handleRequest", request, response); + + //verify that whole image was been sent + verify(ostream, times(6)).write(any(byte[].class), any(int.class), any(int.class)); + } +} + + diff --git a/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/JobsViewTest.java b/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/JobsViewTest.java new file mode 100644 index 000000000..bf3bb5bba --- /dev/null +++ b/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/JobsViewTest.java @@ -0,0 +1,145 @@ +package eu.sqooss.test.service.webadmin; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.when; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.times; +import junit.framework.Assert; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.reflect.Whitebox; + + +import eu.sqooss.impl.service.webadmin.JobsView; +import eu.sqooss.service.logging.LogManager; +import eu.sqooss.service.scheduler.Job; +import eu.sqooss.service.scheduler.Scheduler; +import eu.sqooss.service.scheduler.SchedulerStats; + +@RunWith(PowerMockRunner.class) +@PrepareForTest(Job.class) +public class JobsViewTest { + + @Mock + Scheduler sobjSched; + @Mock + LogManager sobjLogManager; + @Mock + Job job1; + @Mock + Job job2; + + String newline = "\n"; + + @BeforeClass + public static void setUp() { + } + + @Test + public void testExed() { + JobsView jv = new JobsView(null, null); + assertNotNull(jv); + jv.exec(null); + } + + @Test + public void testGetFailedJobsStatsEmpty() { + Whitebox.setInternalState(JobsView.class, sobjSched); + SchedulerStats stats = new SchedulerStats(); + when(sobjSched.getSchedulerStats()).thenReturn(stats); + Assert.assertEquals(stats.getFailedJobTypes(), + JobsView.getFailedJobStats()); + } + + @Test + public void testGetFailedJobsStatsMultiple() { + Whitebox.setInternalState(JobsView.class, sobjSched); + + SchedulerStats stats = new SchedulerStats(); + stats.addFailedJob("Job name 1"); + stats.addFailedJob("Job name 2"); + + when(sobjSched.getSchedulerStats()).thenReturn(stats); + Assert.assertEquals(stats.getFailedJobTypes(), + JobsView.getFailedJobStats()); + Assert.assertEquals("Job name 1", JobsView.getFailedJobStats() + .keySet().toArray()[1]); + Assert.assertEquals(1, + (int) JobsView.getFailedJobStats().get("Job name 2")); + } + @Test + public void testGetWaitingJobsEmpty() { + Whitebox.setInternalState(JobsView.class, sobjSched); + SchedulerStats stats = new SchedulerStats(); + when(sobjSched.getSchedulerStats()).thenReturn(stats); + Assert.assertEquals(stats.getWaitingJobTypes(), + JobsView.getWaitingJobs()); + } + + @Test + public void testGetWaitingJobsMultiple() { + Whitebox.setInternalState(JobsView.class, sobjSched); + + SchedulerStats stats = new SchedulerStats(); + stats.addWaitingJob("Job name 1"); + stats.addWaitingJob("Job name 2"); + + when(sobjSched.getSchedulerStats()).thenReturn(stats); + Assert.assertEquals(stats.getWaitingJobTypes(), + JobsView.getWaitingJobs()); + Assert.assertEquals("Job name 1", JobsView.getWaitingJobs() + .keySet().toArray()[1]); + Assert.assertEquals(1, + (int) JobsView.getWaitingJobs().get("Job name 2")); + } + + + @Test + public void testGetRunningJobsEmpty() { + Whitebox.setInternalState(JobsView.class, sobjSched); + SchedulerStats stats = new SchedulerStats(); + when(sobjSched.getSchedulerStats()).thenReturn(stats); + + Assert.assertEquals(stats.getRunJobs(), JobsView.getRunningJobs()); + } + + @Test + public void testGetRunningJobsMultiple() { + Whitebox.setInternalState(JobsView.class, sobjSched); + SchedulerStats stats = new SchedulerStats(); + stats.addRunJob(job1); + stats.addRunJob(job2); + when(sobjSched.getSchedulerStats()).thenReturn(stats); + + Assert.assertEquals(stats.getRunJobs(), JobsView.getRunningJobs()); + } + + @Test + public void testGetFailedJobsNone() { + Whitebox.setInternalState(JobsView.class, sobjSched); + Job[] jobs = new Job[] {}; + when(sobjSched.getFailedQueue()).thenReturn(jobs); + Assert.assertEquals(jobs, JobsView.getFailedJobs()); + } + + @Test + public void testGetFailedJobsMultiple() { + Whitebox.setInternalState(JobsView.class, sobjSched); + Job[] jobs = new Job[] {job1, job2, null}; + when(sobjSched.getFailedQueue()).thenReturn(jobs); + when(job2.getErrorException()).thenReturn(new IllegalArgumentException("Exception text 2")); + Assert.assertEquals(jobs, JobsView.getFailedJobs()); + } + + @Test + public void testGetSchedulerStats() { + Whitebox.setInternalState(JobsView.class, sobjSched); + JobsView.getSchedulerStats(); + verify(sobjSched, times(1)).getSchedulerStats(); + } +} \ No newline at end of file diff --git a/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/LogsViewTest.java b/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/LogsViewTest.java new file mode 100644 index 000000000..548064341 --- /dev/null +++ b/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/LogsViewTest.java @@ -0,0 +1,63 @@ +package eu.sqooss.test.service.webadmin; + +import static org.mockito.Mockito.when; + +import javax.servlet.http.HttpServletRequest; + +import junit.framework.Assert; + +import org.apache.velocity.VelocityContext; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.osgi.framework.BundleContext; +import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.reflect.Whitebox; + +import eu.sqooss.impl.service.webadmin.LogsView; +import eu.sqooss.service.logging.LogManager; + +@RunWith(PowerMockRunner.class) +public class LogsViewTest { + + @Mock + LogManager sobjLogManager; + @Mock + BundleContext bc; + @Mock + HttpServletRequest req; + + String newline = "\n"; + + @BeforeClass + public static void setUp() { + } + + @Test + public void testExec() { + LogsView lv = new LogsView(bc, new VelocityContext()); + Assert.assertNotNull(lv); + lv.exec(req); + } + + @Test + public void testGetLogsNone() { + Whitebox.setInternalState(LogsView.class, sobjLogManager); + when(sobjLogManager.getRecentEntries()).thenReturn(new String[0]); + Assert.assertTrue(LogsView.getLogs().size() == 0); + + when(sobjLogManager.getRecentEntries()).thenReturn(null); + Assert.assertTrue(LogsView.getLogs().size() == 0); + } + + @Test + public void testGetLogsMultiple() { + Whitebox.setInternalState(LogsView.class, sobjLogManager); + String[] logEntries = {"Log entry 1", "Log entry 2"}; + when(sobjLogManager.getRecentEntries()).thenReturn(logEntries); + Assert.assertTrue(LogsView.getLogs().size() == 2); + Assert.assertEquals("Log entry 1", LogsView.getLogs().get(0)); + } + +} \ No newline at end of file diff --git a/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/PluginsViewTest.java b/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/PluginsViewTest.java new file mode 100644 index 000000000..1b5a789d7 --- /dev/null +++ b/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/PluginsViewTest.java @@ -0,0 +1,259 @@ +package eu.sqooss.test.service.webadmin; + +import static org.junit.Assert.*; +import static org.mockito.BDDMockito.given; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.any; +import static org.mockito.Mockito.when; +import static org.powermock.api.mockito.PowerMockito.mockStatic; + +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.text.DateFormat; +import java.text.ParseException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Collection; +import java.util.Date; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.List; +import java.util.Locale; +import java.util.ResourceBundle; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.concurrent.ConcurrentHashMap; + +import javax.servlet.http.HttpServletRequest; + +import junit.framework.Assert; + +import org.apache.velocity.VelocityContext; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.osgi.framework.BundleContext; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.reflect.Whitebox; + +import eu.sqooss.core.AlitheiaCore; +import eu.sqooss.impl.service.webadmin.AbstractView; +import eu.sqooss.impl.service.webadmin.PluginsView; +import eu.sqooss.impl.service.webadmin.ProjectsView; +import eu.sqooss.service.abstractmetric.AlitheiaPlugin; +import eu.sqooss.service.cluster.ClusterNodeService; +import eu.sqooss.service.db.Bug; +import eu.sqooss.service.db.ClusterNode; +import eu.sqooss.service.db.DBService; +import eu.sqooss.service.db.MailMessage; +import eu.sqooss.service.db.Metric; +import eu.sqooss.service.db.Plugin; +import eu.sqooss.service.db.PluginConfiguration; +import eu.sqooss.service.db.ProjectVersion; +import eu.sqooss.service.db.StoredProject; +import eu.sqooss.service.db.StoredProjectConfig; +import eu.sqooss.service.logging.LogManager; +import eu.sqooss.service.logging.Logger; +import eu.sqooss.service.metricactivator.MetricActivator; +import eu.sqooss.service.pa.PluginAdmin; +import eu.sqooss.service.pa.PluginInfo; +import eu.sqooss.service.scheduler.Scheduler; +import eu.sqooss.service.tds.TDSService; +import eu.sqooss.service.updater.Updater; +import eu.sqooss.service.updater.UpdaterService; +import eu.sqooss.service.updater.UpdaterService.UpdaterStage; + +import org.junit.BeforeClass; +import org.junit.Test; + +import eu.sqooss.impl.service.webadmin.ProjectsView; +import eu.sqooss.service.pa.PluginAdmin; + +@RunWith(PowerMockRunner.class) +@PrepareForTest({Plugin.class}) +public class PluginsViewTest { + @Mock private PluginAdmin pa; + @Mock private AlitheiaPlugin alitheiaPlugin; + @Mock private Plugin plugin; + + @Before + public void setUpTest() + { + Whitebox.setInternalState(PluginsView.class, pa); + } + + @Test + public void testIsPluginsListEmpty() { + Collection col = new ArrayList(); + when(pa.listPlugins()).thenReturn(col); + Assert.assertTrue(PluginsView.isPluginsListEmpty()); + col.add(new PluginInfo()); + Assert.assertFalse(PluginsView.isPluginsListEmpty()); + } + + @Test + public void testGetPluginsList() { + Collection col = new ArrayList(); + when(pa.listPlugins()).thenReturn(col); + Assert.assertTrue(PluginsView.getPluginsList().size() == 0); + col.add(new PluginInfo()); + Assert.assertTrue(PluginsView.getPluginsList().size() == 1); + } + + @Test + public void testGetErrorMessages() { + StringBuilder sb = new StringBuilder(); + Whitebox.setInternalState(PluginsView.class, sb); + + Assert.assertEquals(null, PluginsView.getErrorMessages()); + sb.append("test"); + Assert.assertEquals("test", PluginsView.getErrorMessages()); + } + + @Test + public void testGetSelectedPlugin() { + Assert.assertEquals(null, PluginsView.getSelectedPlugin()); + PluginInfo pi = new PluginInfo(); + Whitebox.setInternalState(PluginsView.class, pi); + Assert.assertEquals(pi, PluginsView.getSelectedPlugin()); + } + + @Test + public void testGetValPropName() { + Assert.assertEquals("", PluginsView.getValPropName()); + String prop = "test"; + Whitebox.setInternalState(PluginsView.class, "reqValPropName", prop); + Assert.assertEquals("test", PluginsView.getValPropName()); + } + + @Test + public void testGetValPropType() { + Assert.assertEquals("", PluginsView.getValPropType()); + String prop = "test"; + Whitebox.setInternalState(PluginsView.class, "reqValPropType", prop); + Assert.assertEquals("test", PluginsView.getValPropType()); + } + + @Test + public void testGetValPropDescr() { + Assert.assertEquals("", PluginsView.getValPropDescr()); + String prop = "test"; + Whitebox.setInternalState(PluginsView.class, "reqValPropDescr", prop); + Assert.assertEquals("test", PluginsView.getValPropDescr()); + } + + @Test + public void testGetValPropValue() { + Assert.assertEquals("", PluginsView.getValPropValue()); + String prop = "test"; + Whitebox.setInternalState(PluginsView.class, "reqValPropValue", prop); + Assert.assertEquals("test", PluginsView.getValPropValue()); + } + + @Test + public void testGetValAction() { + String prop = null; + Whitebox.setInternalState(PluginsView.class, "reqValAction", prop); + Assert.assertEquals("", PluginsView.getValAction()); + prop = "test"; + Whitebox.setInternalState(PluginsView.class, "reqValAction", prop); + Assert.assertEquals("test", PluginsView.getValAction()); + } + + @Test + public void testGetValHashcode() { + Assert.assertEquals("", PluginsView.getValHashcode()); + String prop = "test"; + Whitebox.setInternalState(PluginsView.class, "reqValHashcode", prop); + Assert.assertEquals("test", PluginsView.getValHashcode()); + } + + @Test + public void testGetValShowProp() { + Assert.assertFalse(PluginsView.getValShowProp()); + Whitebox.setInternalState(PluginsView.class, "reqValShowProp", true); + Assert.assertTrue(PluginsView.getValShowProp()); + } + + @Test + public void testGetValShowActv() { + Assert.assertFalse(PluginsView.getValShowActv()); + Whitebox.setInternalState(PluginsView.class, "reqValShowActv", true); + Assert.assertTrue(PluginsView.getValShowActv()); + } + + @Test + public void testGetConfigurationTypes() { + Assert.assertTrue(PluginsView.getConfigurationTypes().length == 4); + } + + @Test + public void testGetPluginMetrics() { + List col = new ArrayList(); + PluginInfo pi = new PluginInfo(); + when(pa.getPlugin(pi)).thenReturn(alitheiaPlugin); + when(alitheiaPlugin.getAllSupportedMetrics()).thenReturn(col); + Assert.assertTrue(PluginsView.getPluginMetrics(pi).size() == 0); + col.add(new Metric()); + Assert.assertTrue(PluginsView.getPluginMetrics(pi).size() == 1); + Assert.assertEquals(null, PluginsView.getPluginMetrics(null)); + } + + @Test + public void testIsPluginMetricsEmpty() { + List col = new ArrayList(); + PluginInfo pi = new PluginInfo(); + when(pa.getPlugin(pi)).thenReturn(alitheiaPlugin); + when(alitheiaPlugin.getAllSupportedMetrics()).thenReturn(null, col); + Assert.assertTrue(PluginsView.isPluginMetricsEmpty(pi)); + Assert.assertTrue(PluginsView.isPluginMetricsEmpty(pi)); + col.add(new Metric()); + Assert.assertFalse(PluginsView.isPluginMetricsEmpty(pi)); + Assert.assertTrue(PluginsView.isPluginMetricsEmpty(null)); + } + + @Test + public void testGetPluginConfiguration() { + Set col = new HashSet(); + PluginInfo pi = new PluginInfo(); + PowerMockito.mockStatic(Plugin.class); + when(Plugin.getPluginByHashcode(pi.getHashcode())).thenReturn(plugin); + when(plugin.getConfigurations()).thenReturn(col); + Assert.assertTrue(PluginsView.getPluginConfiguration(pi).size() == 0); + col.add(new PluginConfiguration()); + Assert.assertTrue(PluginsView.getPluginConfiguration(pi).size() == 1); + Assert.assertEquals(null, PluginsView.getPluginConfiguration(null)); + } + + @SuppressWarnings("unchecked") + @Test + public void testIsPluginConfigurationEmpty() { + Set col = new HashSet(); + PluginInfo pi = new PluginInfo(); + PowerMockito.mockStatic(Plugin.class); + when(Plugin.getPluginByHashcode(pi.getHashcode())).thenReturn(plugin); + when(plugin.getConfigurations()).thenReturn(null, col); + Assert.assertTrue(PluginsView.isPluginConfigurationEmpty(pi)); + Assert.assertTrue(PluginsView.isPluginConfigurationEmpty(pi)); + col.add(new PluginConfiguration()); + Assert.assertFalse(PluginsView.isPluginConfigurationEmpty(pi)); + Assert.assertTrue(PluginsView.isPluginConfigurationEmpty(null)); + } + + @Test + public void testIsDebugOn() { + Assert.assertFalse(PluginsView.isDebugOn()); + Whitebox.setInternalState(PluginsView.class, "DEBUG", true); + Assert.assertTrue(PluginsView.isDebugOn()); + } +} \ No newline at end of file diff --git a/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/ProjectDeleteJobTest.java b/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/ProjectDeleteJobTest.java new file mode 100644 index 000000000..2cec90c00 --- /dev/null +++ b/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/ProjectDeleteJobTest.java @@ -0,0 +1,107 @@ +package eu.sqooss.test.service.webadmin; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.powermock.api.mockito.PowerMockito.mockStatic; + +import java.util.Arrays; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.reflect.Whitebox; + +import eu.sqooss.core.AlitheiaCore; +import eu.sqooss.impl.service.webadmin.ProjectDeleteJob; +import eu.sqooss.service.abstractmetric.AlitheiaPlugin; +import eu.sqooss.service.db.DBService; +import eu.sqooss.service.db.Plugin; +import eu.sqooss.service.db.ProjectVersion; +import eu.sqooss.service.db.StoredProject; +import eu.sqooss.service.db.StoredProjectConfig; +import eu.sqooss.service.pa.PluginAdmin; +import eu.sqooss.service.pa.PluginInfo; + +@RunWith(PowerMockRunner.class) +@PrepareForTest(StoredProjectConfig.class) +public class ProjectDeleteJobTest { + + @Mock private StoredProject project; + @Mock private AlitheiaCore core; + @Mock private DBService db; + @Mock private ProjectVersion v1; + @Mock private ProjectVersion v2; + @Mock private PluginAdmin pa; + @Mock private AlitheiaPlugin ap; + + private ProjectDeleteJob job = new ProjectDeleteJob(core, project); + + @BeforeClass + public static void setUp() + { + } + + @Test + public void testPriority() + { + assertEquals(0xFF, job.priority()); + } + + @Test + public void testToString() + { + job = new ProjectDeleteJob(core, project); + + when(project.toString()).thenReturn("Mock stored project name"); + assertEquals("ProjectDeleteJob - Project:{Mock stored project name}", job.toString()); + } + + @Test + public void testRun() + { + job = new ProjectDeleteJob(core, project); + + when(core.getDBService()).thenReturn(db); + when(db.attachObjectToDBSession(any(StoredProject.class))).thenReturn(project); + when(project.getProjectVersions()).thenReturn(Arrays.asList(new ProjectVersion[] {v1, v2})); + + //Mock code for simulating plugin cleanup + Plugin[] entities = new Plugin[] {new Plugin(), new Plugin()}; + entities[0].setHashcode("hash code of plugin 1"); + doReturn(Arrays.asList(entities)).when(db).doHQL("from Plugin"); + when(core.getPluginAdmin()).thenReturn(pa); + when(pa.getPluginInfo(entities[0].getHashcode())).thenReturn(new PluginInfo()); + when(pa.getPluginInfo(entities[1].getHashcode())).thenReturn(null); + when(pa.getPlugin(any(PluginInfo.class))).thenReturn(ap); + when(pa.getPlugin(null)).thenReturn(null); + + mockStatic(StoredProjectConfig.class); + when(StoredProjectConfig.fromProject(any(StoredProject.class))) + .thenReturn(Arrays.asList(new StoredProjectConfig[] {})); + + try { + Whitebox.invokeMethod(job, "run"); + } catch (Exception e) { + e.printStackTrace(); + } + //verify that plugins were cleaned up + verify(ap, times(1)).cleanup(project); + + //Verify that db is called correctly + verify(db, times(1)).isDBSessionActive(); + verify(db, times(1)).attachObjectToDBSession(any(StoredProject.class)); + + //verify that parents have been cleared + verify(v1, times(1)).getParents(); + verify(v2, times(1)).getParents(); + } + + +} diff --git a/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/ProjectsViewTest.java b/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/ProjectsViewTest.java new file mode 100644 index 000000000..f9cdf5253 --- /dev/null +++ b/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/ProjectsViewTest.java @@ -0,0 +1,508 @@ +package eu.sqooss.test.service.webadmin; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.HashSet; + +import javax.servlet.http.HttpServletRequest; + +import junit.framework.Assert; + +import org.apache.velocity.VelocityContext; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.osgi.framework.BundleContext; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.reflect.Whitebox; + +import eu.sqooss.core.AlitheiaCore; +import eu.sqooss.impl.service.webadmin.ProjectDeleteJob; +import eu.sqooss.impl.service.webadmin.ProjectsView; +import eu.sqooss.service.abstractmetric.AlitheiaPlugin; +import eu.sqooss.service.admin.AdminAction; +import eu.sqooss.service.admin.AdminService; +import eu.sqooss.service.admin.actions.AddProject; +import eu.sqooss.service.admin.actions.UpdateProject; +import eu.sqooss.service.cluster.ClusterNodeService; +import eu.sqooss.service.db.Bug; +import eu.sqooss.service.db.ClusterNode; +import eu.sqooss.service.db.DBService; +import eu.sqooss.service.db.MailMessage; +import eu.sqooss.service.db.ProjectVersion; +import eu.sqooss.service.db.StoredProject; +import eu.sqooss.service.logging.Logger; +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.scheduler.Scheduler; +import eu.sqooss.service.scheduler.SchedulerException; +import eu.sqooss.service.updater.Updater; +import eu.sqooss.service.updater.UpdaterService; +import eu.sqooss.service.updater.UpdaterService.UpdaterStage; + + +@RunWith(PowerMockRunner.class) +@PrepareForTest({ClusterNode.class, + ProjectVersion.class, + Bug.class, + MailMessage.class, + ClusterNode.class, + StoredProject.class + }) +public class ProjectsViewTest { + @Mock private DBService sobjDB; + @Mock private ClusterNodeService sobjClusterNode; + @Mock private StoredProject projectMock; + @Mock private UpdaterService sobjUpdater; + @Mock private AlitheiaPlugin pObj; + @Mock private HttpServletRequest request; + + @Mock private PluginAdmin sobjPA; + @Mock private MetricActivator compMA; + @Mock private Logger sobjLogger; + @Mock private BundleContext bc; + @Mock private VelocityContext vc; + @Mock private AlitheiaCore core; + @Mock private AdminService as; + @Mock private AdminAction aa; + @Mock private Scheduler sobjSched; + + private ProjectsView pView; + + private void initPView(){ + pView = new ProjectsView(bc, vc); + Whitebox.setInternalState(ProjectsView.class, sobjPA ); + Whitebox.setInternalState(ProjectsView.class, compMA); + Whitebox.setInternalState(ProjectsView.class, sobjLogger); + Whitebox.setInternalState(ProjectsView.class, core); + Whitebox.setInternalState(ProjectsView.class, sobjSched); + + + when(core.getAdminService()).thenReturn(as); + when(as.create(UpdateProject.MNEMONIC)).thenReturn(aa); + when(as.create(AddProject.MNEMONIC)).thenReturn(aa); + } + + @Test + public void testGetSelProject() { + initPView(); + StoredProject selProject = new StoredProject(); + Whitebox.setInternalState(pView, selProject); + + assertEquals(selProject, pView.getSelProject()); + } + + //Only test basic exec functionality + @Test + public void testExec() { + initPView(); + + pView.exec(request); + + Assert.assertNull(pView.getSelProject()); + } + + @Test + public void testaddProject() throws Exception { + initPView(); + StoredProject project = new StoredProject(); + PowerMockito.mockStatic(StoredProject.class); + + when(StoredProject.getProjectByName(any(String.class))).thenReturn(project); + + assertEquals(Whitebox.invokeMethod(pView, "addProject", request), project); + + verify(aa, times(5)).addArg(any(String.class), any(Object.class)); + verify(as, times(1)).execute(aa); + verify(aa, times(1)).results(); + } + + @Test + public void testaddProjectFails() throws Exception { + initPView(); + PowerMockito.mockStatic(StoredProject.class); + when(aa.hasErrors()).thenReturn(true); + + Assert.assertNull(Whitebox.invokeMethod(pView, "addProject", request)); + + verify(aa, times(5)).addArg(any(String.class), any(Object.class)); + verify(as, times(1)).execute(aa); + verify(aa, times(1)).errors(); + } + + @Test + public void testSyncPluginNull() throws Exception { + initPView(); + + //Test one of the parameters being null, should not perform + StoredProject selProject = new StoredProject(); + String reqValSyncPlugin = "reqValSyncPlugin"; + + Whitebox.invokeMethod(pView, "syncPlugin", (StoredProject)null, (String)null); + Whitebox.invokeMethod(pView, "syncPlugin", (StoredProject)selProject, (String)null); + Whitebox.invokeMethod(pView, "syncPlugin", (StoredProject)null, (String)reqValSyncPlugin); + + verify(sobjPA, times(0)).getPluginInfo(any(String.class)); + } + + @Test + public void testSyncPluginPInfoNull() throws Exception { + initPView(); + + StoredProject selProject = new StoredProject(); + String reqValSyncPlugin = "reqValSyncPlugin"; + + Whitebox.invokeMethod(pView, "syncPlugin", selProject, reqValSyncPlugin); + + verify(sobjPA, times(1)).getPluginInfo(reqValSyncPlugin); + verify(sobjPA, times(0)).getPlugin(any(PluginInfo.class)); + } + + @Test + public void testSyncPluginPluginNull() throws Exception { + initPView(); + + StoredProject selProject = new StoredProject(); + String reqValSyncPlugin = "reqValSyncPlugin"; + PluginInfo pInfo = new PluginInfo(); + + when(sobjPA.getPluginInfo(reqValSyncPlugin)).thenReturn(pInfo); + + Whitebox.invokeMethod(pView, "syncPlugin", selProject, reqValSyncPlugin); + + verify(sobjPA, times(1)).getPluginInfo(reqValSyncPlugin); + verify(sobjPA, times(1)).getPlugin(pInfo); + } + + @Test + public void testSyncPluginPlugin() throws Exception { + initPView(); + + StoredProject selProject = new StoredProject(); + String reqValSyncPlugin = "reqValSyncPlugin"; + PluginInfo pInfo = new PluginInfo(); + + when(sobjPA.getPluginInfo(reqValSyncPlugin)).thenReturn(pInfo); + when(sobjPA.getPlugin(pInfo)).thenReturn(pObj); + + Whitebox.invokeMethod(pView, "syncPlugin", selProject, reqValSyncPlugin); + + verify(sobjPA, times(1)).getPluginInfo(reqValSyncPlugin); + verify(sobjPA, times(1)).getPlugin(pInfo); + verify(compMA, times(1)).syncMetric(pObj, selProject); + } + + @Test + public void testTriggerAllUpdateNode() throws Exception { + initPView(); + + HashSet projects = new HashSet(); + projects.add(new StoredProject()); + projects.add(new StoredProject()); + + ClusterNode node = new ClusterNode(); + node.setProjects(projects); + PowerMockito.mockStatic(ClusterNode.class); + when(ClusterNode.thisNode()).thenReturn(node); + + Whitebox.invokeMethod(pView, "triggerAllUpdateNode"); + + verify(aa, times(2)).addArg("project", 0L); + } + +// private StoredProject removeProject(StoredProject project) { +// if (project != null) { +// // Deleting large projects in the foreground is very slow +// ProjectDeleteJob pdj = new ProjectDeleteJob(sobjCore, project); +// try { +// sobjSched.enqueue(pdj); +// } catch (SchedulerException e1) { +// errors.add(getErr("e0034")); +// } +// project = null; +// } else { +// errors.add(getErr("e0034")); +// } +// } + + @Test + public void testRemoveProjectNull() throws Exception { + initPView(); + Whitebox.invokeMethod(pView, "removeProject", (StoredProject)null); + + assertEquals(pView.getErrors().get(0), "You must select a project first!"); + } + @Test + public void testRemoveProjectQueuingFails() throws Exception { + initPView(); + StoredProject project = new StoredProject(); + doThrow(new SchedulerException("mock sched exception")) + .when(sobjSched).enqueue(any(ProjectDeleteJob.class)); + + Whitebox.invokeMethod(pView, "removeProject", (StoredProject)project); + assertEquals(pView.getErrors().get(0), "You must select a project first!"); + } + @Test + public void testRemoveProject() throws Exception { + initPView(); + StoredProject project = new StoredProject(); + + Whitebox.invokeMethod(pView, "removeProject", (StoredProject)project); + assertEquals(pView.getErrors().size(), 0); + verify(sobjSched, times(1)).enqueue(any(Job.class)); + } + + + + @Test + public void testTriggerUpdateNull() throws Exception { + initPView(); + + StoredProject project = new StoredProject(); + Whitebox.invokeMethod(pView, "triggerUpdate", project, null); + + verify(aa, times(1)).addArg("project", project.getId()); + verify(as, times(1)).execute(aa); + verify(aa, times(1)).results(); + } + + @Test + public void testTriggerUpdate() throws Exception { + initPView(); + + StoredProject project = new StoredProject(); + when(aa.hasErrors()).thenReturn(true); + + Whitebox.invokeMethod(pView, "triggerUpdate", project, ""); + + verify(aa, times(1)).addArg("project", project.getId()); + verify(aa, times(1)).addArg("updater", ""); + verify(as, times(1)).execute(aa); + verify(aa, times(1)).errors(); + } + + @Test + public void testTriggerUpdateSingleArg() throws Exception { + initPView(); + + StoredProject project = new StoredProject(); + Whitebox.invokeMethod(pView, "triggerUpdate", project); + verify(aa, times(1)).addArg("project", project.getId()); + } + + @Test + public void testGetProjects() { + ClusterNode clusterNode = new ClusterNode(); + + PowerMockito.mockStatic(ClusterNode.class); + when(ClusterNode.thisNode()).thenReturn(clusterNode); + + assertEquals(clusterNode.getProjects(), ProjectsView.getProjects()); + } + + + @Test + public void testGetLastProjectVersionNull() { + ProjectsView.initResources(null); + assertEquals(ProjectsView.getLastProjectVersion(null), "n/a"); + } + + @Test + public void testGetLastProjectVersionNonExisting() { + PowerMockito.mockStatic(ProjectVersion.class); + when(ProjectVersion.getLastProjectVersion(any(StoredProject.class))) + .thenReturn(null); + + StoredProject project = new StoredProject(); + ProjectsView.initResources(null); + + assertEquals(ProjectsView.getLastProjectVersion(project), "n/a"); + } + + + @Test + public void testGetLastProjectVersion() { + ProjectVersion pv = new ProjectVersion(); + pv.setRevisionId("1.0.4"); + StoredProject project = new StoredProject(); + + ProjectsView.initResources(null); + + PowerMockito.mockStatic(ProjectVersion.class); + when(ProjectVersion.getLastProjectVersion(project)) + .thenReturn(pv); + + assertEquals("0(1.0.4)", ProjectsView.getLastProjectVersion(project)); + } + + @Test + public void testGetLastBugNull() { + ProjectsView.initResources(null); + assertEquals(ProjectsView.getLastBug(null), "n/a"); + } + + @Test + public void testGetLastBugNonExisting() { + StoredProject project = new StoredProject(); + + ProjectsView.initResources(null); + + PowerMockito.mockStatic(Bug.class); + when(Bug.getLastUpdate(project)).thenReturn(null); + + assertEquals("n/a", ProjectsView.getLastBug(project)); + } + + @Test + public void testGetLastBug() { + StoredProject project = new StoredProject(); + Bug bug = new Bug(); + bug.setBugID("Mock bug ID"); + + ProjectsView.initResources(null); + + PowerMockito.mockStatic(Bug.class); + when(Bug.getLastUpdate(project)).thenReturn(bug); + + assertEquals("Mock bug ID", ProjectsView.getLastBug(project)); + } + + + @Test + public void testGetLastEmailDateNull() { + ProjectsView.initResources(null); + assertEquals("n/a", ProjectsView.getLastEmailDate(null)); + } + @Test + public void testGetLastEmailDateNonExisting() { + StoredProject project = new StoredProject(); + + ProjectsView.initResources(null); + + PowerMockito.mockStatic(MailMessage.class); + when(MailMessage.getLatestMailMessage(project)).thenReturn(null); + + assertEquals("n/a", ProjectsView.getLastEmailDate(project)); + } + + @Test + public void testGetLastEmailDate() { + StoredProject project = new StoredProject(); + MailMessage mm = new MailMessage(); + Calendar cal = Calendar.getInstance(); + cal.set(2015, 1, 12, 15, 23, 10); + mm.setSendDate(cal.getTime()); + + ProjectsView.initResources(null); + + PowerMockito.mockStatic(MailMessage.class); + when(MailMessage.getLatestMailMessage(project)).thenReturn(mm); + + assertEquals("Thu Feb 12 15:23:10 CET 2015", ProjectsView.getLastEmailDate(project)); + } + + @Test + public void testGetEvalStateNull() { + ProjectsView.initResources(null); + assertEquals("No", ProjectsView.getEvalState(null)); + } + + @Test + public void testGetEvalStateNo() { + when(projectMock.isEvaluated()).thenReturn(false); + ProjectsView.initResources(null); + + assertEquals("No", ProjectsView.getEvalState(projectMock)); + } + + @Test + public void testGetEvalStateYes() { + when(projectMock.isEvaluated()).thenReturn(true); + ProjectsView.initResources(null); + + assertEquals("Yes", ProjectsView.getEvalState(projectMock)); + } + + @Test + public void testGetClusternodeNull() { + ProjectsView.initResources(null); + assertEquals("n/a", ProjectsView.getClusternode(null)); + } + @Test + public void testGetClusternodeLocal() { + ProjectsView.initResources(null); + when(projectMock.getClusternode()).thenReturn(null); + + assertEquals("(local)", ProjectsView.getClusternode(projectMock)); + } + @Test + public void testGetClusternodeRemote() { + ProjectsView.initResources(null); + when(projectMock.getClusternode()).thenReturn(new ClusterNode("Mock node name")); + + assertEquals("Mock node name", ProjectsView.getClusternode(projectMock)); + } + + @Test + public void testGetUpdatersNull() { + ProjectsView.initResources(null); + Whitebox.setInternalState(ProjectsView.class, sobjUpdater); + + assertTrue(ProjectsView.getUpdaters(null, "default").isEmpty()); + } + + @Test + public void testGetUpdaters() { + StoredProject project = new StoredProject(); + ProjectsView.initResources(null); + Whitebox.setInternalState(ProjectsView.class, sobjUpdater); + + HashSet defaultSet = new HashSet(Arrays.asList((Updater)null)); + HashSet inferencetSet = new HashSet(Arrays.asList((Updater)null, (Updater)null)); + HashSet importSet = new HashSet(Arrays.asList((Updater)null, (Updater)null, (Updater)null)); + HashSet parseSet = new HashSet(); + + when(sobjUpdater.getUpdaters(project, UpdaterStage.DEFAULT)).thenReturn(defaultSet); + when(sobjUpdater.getUpdaters(project, UpdaterStage.INFERENCE)).thenReturn(inferencetSet); + when(sobjUpdater.getUpdaters(project, UpdaterStage.IMPORT)).thenReturn(importSet); + when(sobjUpdater.getUpdaters(project, UpdaterStage.PARSE)).thenReturn(parseSet); + + assertEquals(defaultSet, ProjectsView.getUpdaters(project, "default")); + assertEquals(inferencetSet, ProjectsView.getUpdaters(project, "inference")); + assertEquals(importSet, ProjectsView.getUpdaters(project, "import")); + assertEquals(parseSet, ProjectsView.getUpdaters(project, "parse")); + } + + + + @Test + public void testGetClusterName() { + String clusterNodeName = "Mock cluster node name"; + Whitebox.setInternalState(ProjectsView.class, sobjClusterNode); + when(sobjClusterNode.getClusterNodeName()).thenReturn(clusterNodeName); + + assertEquals(ProjectsView.getClusterName(), clusterNodeName); + } + + @Test + public void testGetErrors() { + initPView(); + ArrayList errors = new ArrayList(Arrays.asList("dummy error")); + Whitebox.setInternalState(pView, errors); + + assertEquals(errors, pView.getErrors()); + } +} diff --git a/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/ResultsViewTest.java b/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/ResultsViewTest.java new file mode 100644 index 000000000..5e1178281 --- /dev/null +++ b/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/ResultsViewTest.java @@ -0,0 +1,120 @@ +package eu.sqooss.test.service.webadmin; + +import static org.junit.Assert.assertNotNull; +import static org.mockito.Matchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.velocity.VelocityContext; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleException; +import org.powermock.modules.junit4.PowerMockRunner; +import org.powermock.reflect.Whitebox; + +import eu.sqooss.core.AlitheiaCore; +import eu.sqooss.impl.service.webadmin.ProjectsView; +import eu.sqooss.impl.service.webadmin.ResultsView; +import eu.sqooss.service.admin.AdminAction; +import eu.sqooss.service.admin.AdminService; +import eu.sqooss.service.admin.actions.AddProject; +import eu.sqooss.service.admin.actions.UpdateProject; +import eu.sqooss.service.logging.Logger; + +@RunWith(PowerMockRunner.class) +public class ResultsViewTest { + @Mock private HttpServletRequest request; + @Mock private Bundle bundle; + @Mock private Logger sobjLogger; + + @Mock private BundleContext bc; + @Mock private VelocityContext vc; + @Mock private AlitheiaCore core; + @Mock private AdminService as; + @Mock private AdminAction aa; + + private ResultsView rView; + + private void initRView(){ + rView = new ResultsView(bc, vc); + + Whitebox.setInternalState(ResultsView.class, sobjLogger); + Whitebox.setInternalState(ResultsView.class, core); + + } + + @Test + public void testConstructor() { + initRView(); + + assertNotNull(rView); + } + + @Test + public void testExecStop() throws BundleException { + initRView(); + + when(request.getPathInfo()).thenReturn("/stop"); + when(bc.getBundle(0)).thenReturn(bundle); + + rView.exec(request); + + verify(bundle, times(1)).stop(); + } + + @Test + public void testExecRestart() { + initRView(); + + when(request.getPathInfo()).thenReturn("/restart"); + rView.exec(request); + + verify(vc, times(1)).put(any(String.class), any(String.class)); + } + @Test + public void testExecAddProject() { + initRView(); + + when(request.getPathInfo()).thenReturn("/addproject"); + + rView.exec(request); + } + + @Test + public void testExecDirAddProject() { + initRView(); + + when(core.getAdminService()).thenReturn(as); + when(as.create(AddProject.MNEMONIC)).thenReturn(aa); + when(request.getPathInfo()).thenReturn("/diraddproject"); + + rView.exec(request); + + verify(aa, times(1)).addArg(any(String.class), any(String.class)); + verify(as, times(1)).execute(aa); + } + @Test + public void testExecDirAddProjectFails() { + initRView(); + + when(core.getAdminService()).thenReturn(as); + when(as.create(AddProject.MNEMONIC)).thenReturn(aa); + when(request.getPathInfo()).thenReturn("/diraddproject"); + when(aa.hasErrors()).thenReturn(true); + + rView.exec(request); + + verify(aa, times(1)).addArg(any(String.class), any(String.class)); + verify(aa, times(1)).errors(); + } + + + + +} diff --git a/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/RulesViewTest.java b/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/RulesViewTest.java new file mode 100644 index 000000000..5daacb84f --- /dev/null +++ b/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/RulesViewTest.java @@ -0,0 +1,51 @@ +package eu.sqooss.test.service.webadmin; + +import static org.junit.Assert.assertNotNull; + +import javax.servlet.http.HttpServletRequest; + +import org.apache.velocity.VelocityContext; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.BundleException; +import org.powermock.modules.junit4.PowerMockRunner; + +import eu.sqooss.core.AlitheiaCore; +import eu.sqooss.impl.service.webadmin.RulesView; +import eu.sqooss.service.admin.AdminAction; +import eu.sqooss.service.admin.AdminService; + +@RunWith(PowerMockRunner.class) +public class RulesViewTest { + @Mock private HttpServletRequest request; + @Mock private Bundle bundle; + + @Mock private BundleContext bc; + @Mock private VelocityContext vc; + @Mock private AlitheiaCore core; + @Mock private AdminService as; + @Mock private AdminAction aa; + + private RulesView rView; + + private void initRView(){ + rView = new RulesView(bc, vc); + } + + @Test + public void testConstructor() { + initRView(); + + assertNotNull(rView); + } + + @Test + public void testExec() throws BundleException { + initRView(); + + rView.exec(request); + } +} \ No newline at end of file diff --git a/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/WebadminServiceImplTest.java b/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/WebadminServiceImplTest.java new file mode 100644 index 000000000..6e7f8bb48 --- /dev/null +++ b/alitheia/core/src/test/java/eu/sqooss/test/service/webadmin/WebadminServiceImplTest.java @@ -0,0 +1,122 @@ +package eu.sqooss.test.service.webadmin; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNotSame; +import static org.junit.Assert.assertNull; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyString; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import java.util.Hashtable; + +import javax.servlet.ServletException; + +import junit.framework.Assert; + +import org.apache.velocity.app.VelocityEngine; +import org.junit.BeforeClass; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; +import org.osgi.framework.BundleContext; +import org.osgi.framework.ServiceReference; +import org.osgi.service.http.HttpContext; +import org.osgi.service.http.HttpService; +import org.osgi.service.http.NamespaceException; + +import eu.sqooss.impl.service.webadmin.AdminServlet; +import eu.sqooss.impl.service.webadmin.WebadminServiceImpl; +import eu.sqooss.service.logging.Logger; + +/** + * + * @author Adam Kucera + */ +public class WebadminServiceImplTest { + + static WebadminServiceImpl impl; + @Mock BundleContext bc; + @Mock Logger logger; + + @BeforeClass + public static void setUp() { + impl = spy(new WebadminServiceImpl()); + } + + @Test + public void testWebadminServiceImpl() { + assertNotNull(impl); + } + + @Test + public void testShutDown() { + } + + @Test + public void testMessageOfTheDay() { + assertNull(impl.getMessageOfTheDay()); + impl.setMessageOfTheDay("message"); + assertEquals("message", impl.getMessageOfTheDay()); + assertNotSame("different message", impl.getMessageOfTheDay()); + impl.setMessageOfTheDay("another message"); + assertEquals("another message", impl.getMessageOfTheDay()); + assertNotSame("message", impl.getMessageOfTheDay()); + } + + @Test + public void testStartUpFailure() { + initStartUpTests(); + + when(bc.getServiceReference(HttpService.class.getName())).thenReturn(null); + Assert.assertFalse(impl.startUp()); + } + + @Test + public void testStartUpSuccess() { + initStartUpTests(); + + AdminServlet servlet = mock(AdminServlet.class); + ServiceReference sr = mock(ServiceReference.class); + HttpService httpservice = mock(HttpService.class); + + when(bc.getServiceReference(HttpService.class.getName())).thenReturn(sr); + when(bc.getService(any(ServiceReference.class))).thenReturn(null, httpservice, httpservice); + doReturn(servlet).when(impl).makeAdminServlet( + eq(bc), eq(impl), eq(logger), any(VelocityEngine.class)); + try { + doNothing().when(httpservice).registerServlet(anyString(), + any(AdminServlet.class), any(Hashtable.class), (HttpContext) any()); + } catch (ServletException e) { + e.printStackTrace(); + } catch (NamespaceException e) { + e.printStackTrace(); + } + //test with the null value of http service + Assert.assertTrue(impl.startUp()); + //test with httpservice value + Assert.assertTrue(impl.startUp()); + //test exception + try { + doThrow(new RuntimeException()).when(httpservice).registerServlet(anyString(), + eq(servlet), any(Hashtable.class), (HttpContext) any()); + } catch (ServletException e) { + e.printStackTrace(); + } catch (NamespaceException e) { + e.printStackTrace(); + } + Assert.assertFalse(impl.startUp()); + + } + + protected void initStartUpTests() { + MockitoAnnotations.initMocks(this); + + impl.setInitParams(bc, logger); + } +} diff --git a/alitheia/core/updater.log b/alitheia/core/updater.log new file mode 100644 index 000000000..e69de29bb diff --git a/alitheia/core/webadmin.log b/alitheia/core/webadmin.log new file mode 100644 index 000000000..e69de29bb diff --git a/assignment1 report/software reengineering assignment 1 adam kucera maarten duijn.aux b/assignment1 report/software reengineering assignment 1 adam kucera maarten duijn.aux new file mode 100644 index 000000000..079822e4f --- /dev/null +++ b/assignment1 report/software reengineering assignment 1 adam kucera maarten duijn.aux @@ -0,0 +1,30 @@ +\relax +\@writefile{toc}{\contentsline {section}{\numberline {1}Initial understanding}{1}} +\@writefile{toc}{\contentsline {subsection}{\numberline {1.1}Main features}{1}} +\@writefile{toc}{\contentsline {subsection}{\numberline {1.2}Important source code entities}{1}} +\@writefile{toc}{\contentsline {subsection}{\numberline {1.3}First impression}{1}} +\@writefile{toc}{\contentsline {subsection}{\numberline {1.4}Feasibility of reengineering}{1}} +\@writefile{toc}{\contentsline {section}{\numberline {2}Exceptional entities}{2}} +\@writefile{toc}{\contentsline {subsection}{\numberline {2.1}Inheritance structure}{2}} +\@writefile{toc}{\contentsline {subsection}{\numberline {2.2}Exceptional packages}{2}} +\@writefile{toc}{\contentsline {subsection}{\numberline {2.3}Exceptional classes and methods}{2}} +\@writefile{toc}{\contentsline {section}{\numberline {3}Details}{2}} +\@writefile{toc}{\contentsline {subsection}{\numberline {3.1}Basic elements to compose a scene}{2}} +\@writefile{toc}{\contentsline {subsection}{\numberline {3.2}Rendering of scenes}{3}} +\@writefile{toc}{\contentsline {section}{\numberline {4}Problem detection}{3}} +\@writefile{toc}{\contentsline {subsection}{\numberline {4.1}Single Responsibility Principle violations}{3}} +\@writefile{toc}{\contentsline {subsection}{\numberline {4.2}Liskov Substitution Principle violation}{3}} +\@writefile{toc}{\contentsline {subsection}{\numberline {4.3}Open Closed Principle violation}{3}} +\@writefile{lof}{\contentsline {figure}{\numberline {1}{\ignorespaces Class diagram of AbstractMetric and MetricActivator packages}}{4}} +\newlabel{fig:classmetrics}{{1}{4}} +\@writefile{lof}{\contentsline {figure}{\numberline {2}{\ignorespaces Package diagram showing a subset of the packages in Alitheia Core}}{4}} +\newlabel{fig:package}{{2}{4}} +\@writefile{toc}{\contentsline {subsection}{\numberline {4.4}Dependency Inversion Principle violation}{4}} +\@writefile{toc}{\contentsline {subsection}{\numberline {4.5}Acyclic Dependency Principle violation}{4}} +\@writefile{toc}{\contentsline {subsection}{\numberline {4.6}Duplicated Code}{5}} +<<<<<<< HEAD +======= +\@writefile{toc}{\contentsline {subsection}{\numberline {1.1}Data processing}{1}} +>>>>>>> cf99e5c... Added report base, first diagrams +======= +>>>>>>> 88686ee... Added diagrams and updated report diff --git a/assignment1 report/software reengineering assignment 1 adam kucera maarten duijn.log b/assignment1 report/software reengineering assignment 1 adam kucera maarten duijn.log new file mode 100644 index 000000000..392fa445d --- /dev/null +++ b/assignment1 report/software reengineering assignment 1 adam kucera maarten duijn.log @@ -0,0 +1,222 @@ +<<<<<<< HEAD +<<<<<<< HEAD +This is pdfTeX, Version 3.1415926-2.5-1.40.14 (TeX Live 2013/Debian) (format=pdflatex 2014.10.4) 1 DEC 2014 15:05 +======= +This is pdfTeX, Version 3.1415926-2.5-1.40.14 (TeX Live 2013/Debian) (format=pdflatex 2014.10.4) 24 NOV 2014 10:56 +>>>>>>> cf99e5c... Added report base, first diagrams +======= +This is pdfTeX, Version 3.1415926-2.5-1.40.14 (MiKTeX 2.9) (preloaded format=pdflatex 2014.9.9) 3 DEC 2014 15:56 +>>>>>>> 88686ee... Added diagrams and updated report +entering extended mode +**software*reengineering*assignment*1*adam*kucera*maarten*duijn.tex + +("C:\Users\Maarten\git\Alitheia-Core\assignment1 report\software reengineering +assignment 1 adam kucera maarten duijn.tex" +LaTeX2e <2011/06/27> +Babel and hyphenation patterns for english, afrikaans, ancientgreek, ar +abic, armenian, assamese, basque, bengali, bokmal, bulgarian, catalan, coptic, +croatian, czech, danish, dutch, esperanto, estonian, farsi, finnish, french, ga +lician, german, german-x-2013-05-26, greek, gujarati, hindi, hungarian, iceland +ic, indonesian, interlingua, irish, italian, kannada, kurmanji, latin, latvian, + lithuanian, malayalam, marathi, mongolian, mongolianlmc, monogreek, ngerman, n +german-x-2013-05-26, nynorsk, oriya, panjabi, pinyin, polish, portuguese, roman +ian, russian, sanskrit, serbian, slovak, slovenian, spanish, swedish, swissgerm +an, tamil, telugu, turkish, turkmen, ukenglish, ukrainian, uppersorbian, usengl +ishmax, welsh, loaded. +("C:\Program Files (x86)\MiKTeX 2.9\tex\latex\base\article.cls" +Document Class: article 2007/10/19 v1.4h Standard LaTeX document class +("C:\Program Files (x86)\MiKTeX 2.9\tex\latex\base\size11.clo" +File: size11.clo 2007/10/19 v1.4h Standard LaTeX file (size option) +<<<<<<< HEAD +======= +(/usr/share/texlive/texmf-dist/tex/latex/base/size12.clo +File: size12.clo 2007/10/19 v1.4h Standard LaTeX file (size option) +>>>>>>> cf99e5c... Added report base, first diagrams +======= +>>>>>>> 88686ee... Added diagrams and updated report +) +\c@part=\count79 +\c@section=\count80 +\c@subsection=\count81 +\c@subsubsection=\count82 +\c@paragraph=\count83 +\c@subparagraph=\count84 +\c@figure=\count85 +\c@table=\count86 +\abovecaptionskip=\skip41 +\belowcaptionskip=\skip42 +\bibindent=\dimen102 +) +("C:\Program Files (x86)\MiKTeX 2.9\tex\latex\preprint\fullpage.sty" +Package: fullpage 1999/02/23 1.1 (PWD) +\FP@margin=\skip43 +) +("C:\Program Files (x86)\MiKTeX 2.9\tex\latex\graphics\graphicx.sty" +Package: graphicx 1999/02/16 v1.0f Enhanced LaTeX Graphics (DPC,SPQR) + +("C:\Program Files (x86)\MiKTeX 2.9\tex\latex\graphics\keyval.sty" +Package: keyval 1999/03/16 v1.13 key=value parser (DPC) +\KV@toks@=\toks14 +) +("C:\Program Files (x86)\MiKTeX 2.9\tex\latex\graphics\graphics.sty" +Package: graphics 2009/02/05 v1.0o Standard LaTeX Graphics (DPC,SPQR) + +("C:\Program Files (x86)\MiKTeX 2.9\tex\latex\graphics\trig.sty" +Package: trig 1999/03/16 v1.09 sin cos tan (DPC) +) +("C:\Program Files (x86)\MiKTeX 2.9\tex\latex\00miktex\graphics.cfg" +File: graphics.cfg 2007/01/18 v1.5 graphics configuration of teTeX/TeXLive +) +Package graphics Info: Driver file: pdftex.def on input line 91. + +("C:\Program Files (x86)\MiKTeX 2.9\tex\latex\pdftex-def\pdftex.def" +File: pdftex.def 2011/05/27 v0.06d Graphics/color for pdfTeX + +("C:\Program Files (x86)\MiKTeX 2.9\tex\generic\oberdiek\infwarerr.sty" +Package: infwarerr 2010/04/08 v1.3 Providing info/warning/error messages (HO) +) +("C:\Program Files (x86)\MiKTeX 2.9\tex\generic\oberdiek\ltxcmds.sty" +Package: ltxcmds 2011/11/09 v1.22 LaTeX kernel commands for general use (HO) +) +\Gread@gobject=\count87 +)) +\Gin@req@height=\dimen103 +\Gin@req@width=\dimen104 +<<<<<<< HEAD +======= +(/usr/share/texlive/texmf-dist/tex/latex/parskip/parskip.sty +Package: parskip 2001/04/09 non-zero parskip adjustments +>>>>>>> cf99e5c... Added report base, first diagrams +======= +>>>>>>> 88686ee... Added diagrams and updated report +) +("C:\Users\Maarten\git\Alitheia-Core\assignment1 report\software reengineering +assignment 1 adam kucera maarten duijn.aux") +LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 11. +LaTeX Font Info: ... okay on input line 11. +LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 11. +LaTeX Font Info: ... okay on input line 11. +LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 11. +LaTeX Font Info: ... okay on input line 11. +LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 11. +LaTeX Font Info: ... okay on input line 11. +LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 11. +LaTeX Font Info: ... okay on input line 11. +LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 11. +LaTeX Font Info: ... okay on input line 11. + +("C:\Program Files (x86)\MiKTeX 2.9\tex\context\base\supp-pdf.mkii" +[Loading MPS to PDF converter (version 2006.09.02).] +\scratchcounter=\count88 +\scratchdimen=\dimen105 +\scratchbox=\box26 +\nofMPsegments=\count89 +\nofMParguments=\count90 +\everyMPshowfont=\toks15 +\MPscratchCnt=\count91 +\MPscratchDim=\dimen106 +\MPnumerator=\count92 +\makeMPintoPDFobject=\count93 +\everyMPtoPDFconversion=\toks16 +) +LaTeX Font Info: External font `cmex10' loaded for size +(Font) <12> on input line 14. +LaTeX Font Info: External font `cmex10' loaded for size +(Font) <8> on input line 14. +LaTeX Font Info: External font `cmex10' loaded for size +(Font) <6> on input line 14. + [1 + +{C:/ProgramData/MiKTeX/2.9/pdftex/config/pdftex.map}] [1] [2] [3] + +File: class_cyclic_dependency.png Graphic file (type png) + + +Package pdftex.def Info: class_cyclic_dependency.png used on input line 102. +(pdftex.def) Requested size: 433.02109pt x 140.32532pt. + + +File: package_diagram_core_no_impl_no_core.png Graphic file (type png) + + +Package pdftex.def Info: package_diagram_core_no_impl_no_core.png used on input + line 109. +(pdftex.def) Requested size: 429.10208pt x 134.50217pt. + [4 ] [5] +("C:\Users\Maarten\git\Alitheia-Core\assignment1 report\software reengineering +assignment 1 adam kucera maarten duijn.aux") ) +Here is how much of TeX's memory you used: + 1160 strings out of 493921 + 16357 string characters out of 3144871 + 67085 words of memory out of 3000000 + 4490 multiletter control sequences out of 15000+200000 + 7887 words of font info for 28 fonts, out of 3000000 for 9000 + 841 hyphenation exceptions out of 8191 + 27i,7n,19p,717b,213s stack positions out of 5000i,500n,10000p,200000b,50000s + +Output written on "software reengineering assignment 1 adam kucera maarten duij +n.pdf" (6 pages, 216671 bytes). +PDF statistics: + 39 PDF objects out of 1000 (max. 8388607) + 0 named destinations out of 1000 (max. 500000) + 11 words of extra memory for PDF output out of 10000 (max. 10000000) +<<<<<<< HEAD +======= +LaTeX Font Info: Checking defaults for OML/cmm/m/it on input line 10. +LaTeX Font Info: ... okay on input line 10. +LaTeX Font Info: Checking defaults for T1/cmr/m/n on input line 10. +LaTeX Font Info: ... okay on input line 10. +LaTeX Font Info: Checking defaults for OT1/cmr/m/n on input line 10. +LaTeX Font Info: ... okay on input line 10. +LaTeX Font Info: Checking defaults for OMS/cmsy/m/n on input line 10. +LaTeX Font Info: ... okay on input line 10. +LaTeX Font Info: Checking defaults for OMX/cmex/m/n on input line 10. +LaTeX Font Info: ... okay on input line 10. +LaTeX Font Info: Checking defaults for U/cmr/m/n on input line 10. +LaTeX Font Info: ... okay on input line 10. +LaTeX Font Info: External font `cmex10' loaded for size +(Font) <14.4> on input line 13. +LaTeX Font Info: External font `cmex10' loaded for size +(Font) <7> on input line 13. + [1 + +{/var/lib/texmf/fonts/map/pdftex/updmap/pdftex.map}] +LaTeX Font Info: Try loading font information for OMS+cmr on input line 24. + +(/usr/share/texlive/texmf-dist/tex/latex/base/omscmr.fd +File: omscmr.fd 1999/05/25 v2.5h Standard LaTeX font definitions +) +LaTeX Font Info: Font shape `OMS/cmr/m/n' in size <12> not available +(Font) Font shape `OMS/cmsy/m/n' tried instead on input line 24. + [1] +(./software reengineering assignment 1 adam kucera maarten duijn.aux) ) +Here is how much of TeX's memory you used: + 264 strings out of 494985 + 3751 string characters out of 6180356 + 50248 words of memory out of 5000000 + 3552 multiletter control sequences out of 15000+600000 + 6627 words of font info for 24 fonts, out of 8000000 for 9000 + 36 hyphenation exceptions out of 8191 + 22i,7n,19p,635b,185s stack positions out of 5000i,500n,10000p,200000b,80000s + +Output written on "software reengineering assignment 1 adam kucera maarten duij +n.pdf" (2 pages, 50428 bytes). +PDF statistics: + 27 PDF objects out of 1000 (max. 8388607) + 18 compressed objects within 1 object stream + 0 named destinations out of 1000 (max. 500000) + 1 words of extra memory for PDF output out of 10000 (max. 10000000) +>>>>>>> cf99e5c... Added report base, first diagrams +======= +>>>>>>> 88686ee... Added diagrams and updated report + diff --git a/assignment1 report/software reengineering assignment 1 adam kucera maarten duijn.tex b/assignment1 report/software reengineering assignment 1 adam kucera maarten duijn.tex new file mode 100644 index 000000000..c4c5a3061 --- /dev/null +++ b/assignment1 report/software reengineering assignment 1 adam kucera maarten duijn.tex @@ -0,0 +1,187 @@ +<<<<<<< HEAD +\documentclass[a4paper,11pt,titlepage]{article} +\usepackage{fullpage} +\PassOptionsToPackage{hyphens}{url} +\usepackage{graphicx} +%\usepackage[parfill]{parskip} +======= +\documentclass[a4paper,12pt,titlepage]{article} +\usepackage{fullpage} +\PassOptionsToPackage{hyphens}{url} +\usepackage[parfill]{parskip} +>>>>>>> cf99e5c... Added report base, first diagrams + +% define the title +\author{Adam Ku\v{c}era 4406028\\Maarten Duijn 1517279} +\title{Reverse Engineering and Detection Report} +\date{\today} +\begin{document} + +% generates the title +\maketitle + +\section{Initial understanding} +<<<<<<< HEAD +\subsection{Main features} +The essential part of the application is the Alitheia Core module itself, which provides the main functionalities and interfaces for plug-ins and other extensions. The most important features of the core are the following: initialization of the application and all related services, providing an interface for plugins, which can calculate project metrics, or import raw data, providing a web interface for administration and job submission, and lastly scheduling the metrics and other jobs parallel to each other. + +% +%\begin{itemize} +%\item Initialization of the application and all related services. +%\item Providing an interface for plugins, which can calculate project metrics, or import raw data. +%\item Providing a web interface for administration and job submission. +%\item Scheduling the metrics and other jobs parallel to each other. +%\end{itemize} + +\subsection{Important source code entities} +The product is split up into various services all individually manageable as an OSGi service. It thus stands to reason that the interface that all these services implement is one of the most import entities, and the class that manages the services is as well. These are AlitheiaCoreService respectively AlitheiaCore in the core package. + +Another important entity is the eu.sqoos.service.db package, this package holds the database service interface as well as all the objects used by the object relational mapper. + +The main purpose of Aliteia core is to enable software engineering research. It does this by letting plugins calculate metrics over projects based on data from several sources. As a consequence the interface for plugins: AlitheiaPlugin and the class implementing basic plugin functionality: AbstractMetric belong in the list of the most important entities. + +\subsection{First impression} +The very first impression of the software we got was by inspecting the website which had some clear high level documentation but seemed to be very out of date. This documentation trend continues throughout the project, overall the software seems to be moderately well documented but there is definitely room for improvement. Some examples are: not being able to open the database schema without debugging the software, various commenting styles and missing method, package or class documentation. + +We did like the overall design of the software itself, it seems straightforward with a good level of abstraction and a clear separation of responsibilities. The testing for the software on the other and was very underwhelming, unit tests are very scarce, and even when they do exist are short, not documented and have no clear result message. The worst part about this is that the implementation reflects this fact, in general, code is not easily testable due to long and complex methods. + +\subsection{Feasibility of reengineering} +We do think reengineering is feasible, the main reason for this is that the overall architecture looks quite good. The product is well designed, relatively easy to understand and for a research product easy to run. The design patterns used throughout the product are applied in an appropriate way which makes the product relatively maintainable, extensible and flexible. + +\section{Exceptional entities} +\subsection{Inheritance structure} +The general inheritance structure is that when a class is used in some way by other classes it gets an interface that is placed in an abstract package with other interfaces for classes from the same package. When a class is not used by classes outside the package but only by classes inside the package, an interface is defined for this class in the packages itself. + +Plugins and metrics used in calculation and data retrieval have to implement a special interface or extend a class already providing certain basic methods making the software easily extendible. + +\subsection{Exceptional packages} +Package eu.sqooss.service.db is the biggest package in the application, as it contains the highest number of classes. The whole package is responsible for maintaining the database connection and most of the classes represent Data Access Objects mapping different application entities to the database. These DAOs usually have a lot of getter and setter methods, which is diagnosed as a flaw by the tools, but we do not consider as a big problem, as DAOs usually look that way. + +On the other hand, package eu.sqooss.plugins.updater.svn responsible for synchronizing metadata in database with Subversion repository contains only one very long class. + +Package eu.sqooss.service.util contains basic utility functions e.g. manipulating with strings or files. However, this package does not follow the inheritance structure mentioned above and it already contains implemented functions. Similar case might be main eu.sqooss.core, which provides initialization and service loading functionalities and therefore does not implement any interface. + +\subsection{Exceptional classes and methods} +We found several classes, which might be considered as God classes, which means, that these classes have too much responsibilities. Classic example of such a class is AlitheiaCore, which is responsible for loading and starting all of the application components. Other classes also resemble the God class anti-pattern. Class AbstractMetric is such a case, as it is responsible for a lot of common features connected to metrics, is widely used throughout the application and also uses a lot of methods from other classes. + +Classes ProjectView or PluginsView are part of the presentation layer of the application and therefore contain rendering methods. However, these rendering methods are usually very long and sometimes mix the presentation data itself with business logic. + +%There are more classes with pretty long and complex methods. For example UpdateServiceImpl contains very long and complex update() method, which is responsible for the whole updating process, when something changes in raw data sources. This method should at least be split into different methods, as it is performing different tasks in sequence. +% +%More very complex methods exist in the application. In class ContributionMetricImpl there is quite long run() method with deeply nested statements. Also Structural class contains serveral complex methods, which are e.g. using if statements inside switch statements, which has bad effect on the complexity. + +SVNUpdaterImpl class might have a feature envy, as it uses a lot of methods from other objects. On the other hand FileUtils class is exactly the opposite, as it is used by a lot of other classes. That is however expected from an utility class. + +\section{Details} +\subsection{Basic elements to compose a scene} +All basic HTML sources for a scene are in the src/main/resources folder. These files are calling rendering methods mostly from eu.sqooss.impl.service.webadmin package, but also from other packages, from which the information should be viewed. All of these HTML files include the same basic structural files such as header.inc, menu.inc or sidebar.inc. It means, that all these files contain the same head and tail, which might mean possible duplicate code and option for future refactoring. + +\subsection{Rendering of scenes} +The application is leveraging Apache Velocity to render its web interface. AlitheiaCore class first starts the webadmin service, which initializes HTTP service and starts the Velocity, which loads all the template resources. Template resources then call respective rendering methods for the information it needs to display, e.g. RenderFailedJobs(). The interaction with the user is handled via GET and POST requests using AdminServlet class. +% +%\subsection{Collision detection} +%We are not exactly sure what is meant by a collision in this domain, so we suppose, that it is an event, when the raw project source is updated and therefore there is a conflict between this raw data and metadata in application database. An update of the database is handled by given Updater for the specific raw source. Such an update is started only manually from the interface, ProjectView’s render() method parses the request to update an project and this update is performed through UpdateProject class in the Admin service. + +\section{Problem detection} + +\subsection{Single Responsibility Principle violations} +The AbstractMetric class is a classic example of an SRP violation, the class provides implementations for the OSGi bundle information retrieval, logging services, database access methods and more. The problem could be said to lie in AlitheiaPlugin as well since the interface forces implementation in a single class to a certain degree. The best solution would be to split up the interface and thus class hierarchy and make each responsible for a single feature (ie. logging, database access, plugin management) + +Many of the render and update methods in the product are very long indicating there might be problems with the SRP. We picked two of these: PluginsView render and UpdateServiceImpl update as examples of SRP violation. The render method is extraordinarily long with 867 lines of code, has a high complexity with a maximum nesting of 10 and places 415 outgoing method calls. The method is responsible for rendering different views from lists of plugins and rendering HTML for updating and configuration. By splitting up these different functions into a number of separate methods responsible for a single function most of the problems will be solved. + +The same goes for the UpdaterServiceImpl update method, with 226 liines of code and a cyclometic complexity of 36. The method performs a topological sort which should most certainly be a standalone method. Such an algorithm is a very likely candidate for bugs and should be easily testable. + +\subsection{Liskov Substitution Principle violation} +An example of an LSP violation is the class UpdaterJob, which is a descendant of Job class violates the LSP, more specifically its usage in the application. When the update job is started in update() method in UpdateServiceImpl class, it is always added as a dependency to another already scheduled update jobs. It iterates over all scheduled jobs and using instanceof operator, it asks only for instances of UpdaterJob class. + +The idea of course makes sense, because other scheduled jobs of other types do not depend on these update jobs, however this is a violation of the LSP, because to follow this principle, all jobs should look to the same to the application and instanceof should not be necessary to use. + +\subsection{Open Closed Principle violation} +We have been able to detect one small violation of the OCP. It concerns the class UpdaterServiceImpl, which extends the class AlitheiaCoreService. This parent class has an explicit requirement that all its descendants should implement an empty constructor (which is different from omitting the constructor implementation, which results into calling the constructor of super class). This might cause problems in the future, as this means, that UpdaterServiceImpl might not be used in place of all AlitheiaCoreService subtypes thus it violates the OCP. + +\subsection{Dependency Inversion Principle violation} +DBServiceImpl class contains implementations for all different types of databases, which is a violation of DIP. In Java, the access to these databases is more or less the same thanks to JDBC driver, but exact implementation for each technology should be in different class and a super interface or an abstract class should be introduced. That would make it easier to add a new technology to the system without the need of editing (and testing) the whole complex DBServiceImpl class. + +Being more abstract, the whole application might not be using only relational databases as the storage in the future, but also different storage type (for example file storage). Therefore another interface representing a DataAccess class could be added and the database service would be just implementation of this interface. Possible change of the storage technology in the future would be then very easy. + +\subsection{Acyclic Dependency Principle violation} + +\begin{figure} +\includegraphics[scale=0.3]{class_cyclic_dependency} +\centering +\caption{Class diagram of AbstractMetric and MetricActivator packages} +\label{fig:classmetrics} +\end{figure} + +\begin{figure} +\includegraphics[scale=0.25]{package_diagram_core_no_impl_no_core} +\centering +\caption{Package diagram showing a subset of the packages in Alitheia Core} +\label{fig:package} +\end{figure} + +A clear example of a violation of the Acyclic Dependency Principle is the relation between the AbstractMetric and MetricActivator packages. As shown in figure \ref{fig:classmetrics}, classes in both packages are used by each other and thus dependent on each other. There seem to be more problems regarding the AbstractMetric package as this package has another cyclic dependency with the pa package, shown in figure \ref{fig:package}. The AbstractMetric package depends on the pa package and vice versa. + +\subsection{Duplicated Code} +The Don't Repeat Yourself principle is violated in a number of places throughout the product. The most clear example of this is the duplication in the DBServiceImpl class. In this class the doSQL method with approximately 30 lines is effectively copied into the callProcedure method. + +A less severe type of duplication: sibling duplication is demonstrated by the SVNUpdaterImpl class, in this class the replayLog method is very similar to the GitUpdater replayLog method. The duplication is understandable, one might want to clearly separate functionality in the raw data handling classes. However by introducing a separate class higher in the class hierarchy for versioning systems with similar functionality (ie. Git, SVN, Bazaar) this duplication would not be necessary. + + +======= +%From about: +The Alitheia Core tool is an extensible platform for software quality analysis that is designed specifically to facilitate software engineering research on large and diverse data sources. It integrates data collection and preprocessing phases with an array of analysis services, and presents the researcher with an easy to use extension mechanism. Alitheia Core aims to be the basis of an ecosystem of shared tools and research data that will enable researchers to focus on their research questions at hand, rather than spend time on re-implementing analysis tools. + +More specifically, Alitheia is the name of a platform, developed by the SQO-OSS project, for the automated objective evaluation of the quality of Open Source projects. By analyzing both the soft and the hard project artifacts (the project source code history is "hard" while the mailing lists, bug tracker entries and other human communications are "soft") the Alitheia software will produce a broader and more comprehensive picture of the quality and viability of each Open Source project than tools that examine only the product of the project. + +%From Documentation: +Alitheia Core can process 3 types of data: +\begin{itemize} +\item Revisions from source code management systems +\item Emails from mailing lists +\item Bugs from bug tracking databases +\end{itemize} + +%What are the main features of the program? +What are the main features of the program? +\begin{itemize} +\item Calculate metrics +\item Provide an interface for plugins to calculate metrics +\item Interpret data from a wide range of sources +\item Provide a REST interface that allows for accessing the stored metadata and metric results in a structured manner +\item Provide error recovery tools: logs, metadata consistency. %TODO weird feature but important, see: http://www.sqo-oss.org/run +\item Update functionality %TODO really a feature? +\end{itemize} + +%Which are the important source code entities? +Which are the important source code entities? +%TODO verfiy these +\begin{itemize} +\item Calculate metrics %TODO exact entity please +\item Project: It represents a project that can have multiple project versions, multiple mailing lists and multiple bug reports + +\item Developer: A developer is a person that has contributed to the project. + +\item ProjectFile: A state in a file's development history. + +\item MailingList: A mailing list represents a collection of MailMessages that are sent to (or carbon-copied to) a common email address. + +\item Plugin : Represents and holds information about a metric plug-in. A Plugin can define several Metrics, which are uniquely identified by a mnemonic + +\item MetricMeasurement : is the entity that encapsulates all metric results. +\end{itemize} + + +%What is your first impression of the quality of the design and implementation (also think of documentation, tests, etc.)? +\begin{itemize} +\item Documentation (website: \ur{http://www.sqo-oss.org/roadmap}) has quite a number of dead links, and is outdated for example the database schema was posted on 02/11/2010 +\item Coding Style: supposedly java standard style, %TODO how well is this standard followed +\item JavaDoc: each function requires: parameters, return and exceptions %TODO how well is the javadoc followed +\end{itemize} +%Do you think a reengineering is feasible? + + +%TODO Loads of uses of get, according to Uniform Access Principle this is bad +>>>>>>> cf99e5c... Added report base, first diagrams + +\end{document} \ No newline at end of file diff --git a/doc/db-schema.pdf b/doc/db-schema.pdf index e69de29bb..c6663768d 100644 Binary files a/doc/db-schema.pdf and b/doc/db-schema.pdf differ diff --git a/doc/db-schema.sh b/doc/db-schema.sh index 59e83b875..8896e576e 100755 --- a/doc/db-schema.sh +++ b/doc/db-schema.sh @@ -2,16 +2,16 @@ #To produce: place UMLGraph.jar in this directory and run # -if [ ! -e UMLGraph.jar ]; then - curl -o UmlGraph.jar http://search.maven.org/remotecontent?filepath=org/umlgraph/umlgraph/5.6/umlgraph-5.6.jar - #echo Copy UMLGraph.jar to `pwd` and re-run +#if [ ! -e UmlGraph.jar ]; then +# curl -o UmlGraph.jar http://search.maven.org/remotecontent?filepath=org/umlgraph/umlgraph/5.6/umlgraph-5.6.jar + #echo Copy UmlGraph.jar to `pwd` and re-run #exit 1 -fi +#fi cwd=`pwd` -cp UMLGraph.jar ../alitheia/core/src/main/java/eu/sqooss/service/db +#cp UmlGraph.jar ../alitheia/core/src/main/java/eu/sqooss/service/db cd ../alitheia/core/src/main/java/eu/sqooss/service/db -java -jar UmlGraph.jar -attributes -private -hide "Ohloh|DAObject|FileGroup|ProjectVersionParentId|DBService|StoredProjectConfig" *.java +/usr/java/jre1.8.0_25/bin/java -jar /usr/local/lib/UmlGraph.jar -attributes -private -hide "Ohloh|DAObject|FileGroup|ProjectVersionParentId|DBService|StoredProjectConfig" *.java cat graph.dot |grep -v STATE|grep -v MASK|grep -v SCM_ROOT|grep -v DEFAULT >graph1.dot mv graph1.dot graph.dot dot -Tpdf graph.dot >db-schema.pdf diff --git a/metrics/contrib/maven-eclipse.xml b/metrics/contrib/maven-eclipse.xml new file mode 100644 index 000000000..9ff04ecea --- /dev/null +++ b/metrics/contrib/maven-eclipse.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/plug-ins/git/alitheia.log b/plug-ins/git/alitheia.log new file mode 100644 index 000000000..e69de29bb diff --git a/plug-ins/git/hibernate.log b/plug-ins/git/hibernate.log new file mode 100644 index 000000000..e69de29bb diff --git a/plug-ins/git/perf.log b/plug-ins/git/perf.log new file mode 100644 index 000000000..e69de29bb diff --git a/plug-ins/git/rest.log b/plug-ins/git/rest.log new file mode 100644 index 000000000..e69de29bb diff --git a/plug-ins/git/updater.log b/plug-ins/git/updater.log new file mode 100644 index 000000000..e69de29bb diff --git a/plug-ins/git/webadmin.log b/plug-ins/git/webadmin.log new file mode 100644 index 000000000..e69de29bb diff --git a/pom.xml b/pom.xml index 12683f1ee..5c25ab045 100644 --- a/pom.xml +++ b/pom.xml @@ -1,63 +1,64 @@ - 4.0.0 - eu - sqooss - 0.95-SNAPSHOT + 4.0.0 + eu + sqooss + 0.95-SNAPSHOT - The SQO-OSS project + The SQO-OSS project - Alitheia Core is a platform for conducting software engineering studies. - It integrates data from various sources such as from SVN, mailing lists and bug databases. + Alitheia Core is a platform for conducting software engineering studies. + It integrates data from various sources such as from SVN, mailing lists and bug databases. - Being a platform, and not a concrete implementation, means that by writing the appropriate plug-ins, - you can instruct Alitheia Core to produce any measurements you are interested into and maybe - integrate those measurements in high level quality evaluations. + Being a platform, and not a concrete implementation, means that by writing the appropriate plug-ins, + you can instruct Alitheia Core to produce any measurements you are interested into and maybe + integrate those measurements in high level quality evaluations. - http://www.sqo-oss.org + http://www.sqo-oss.org - 2006 + 2006 - - Organisation for Free and Open Source Software Greece - http://www.ellak.gr/ - + + Organisation for Free and Open Source Software Greece + http://www.ellak.gr/ + - - - BSD 2-clause - http://en.wikipedia.org/wiki/BSD_licenses - - + + + BSD 2-clause + http://en.wikipedia.org/wiki/BSD_licenses + + - - - ac-main - Alitheia Core Main Repository - dav:https://maven.sqo-oss.org/ - - - ac-snapshot - Alitheia Core snapshot repository - dav:https://maven.sqo-oss.org/snapshot - - + + + ac-main + Alitheia Core Main Repository + dav:https://maven.sqo-oss.org/ + + + ac-snapshot + Alitheia Core snapshot repository + dav:https://maven.sqo-oss.org/snapshot + + - - 8080 - 8443 + + + 3030 + 3443 - - + + + slow @@ -82,175 +83,183 @@ tmp - pom + pom - - - JBoss - jboss - http://repository.jboss.org/nexus/content/groups/public/ - - + + + JBoss + jboss + http://repository.jboss.org/nexus/content/groups/public/ + + - - alitheia - plug-ins - metrics - external - parsers - web - + + alitheia + plug-ins + metrics + external + parsers + web + - - - gousiosg - Georgios Gousios - gousiosg@gmail.com - http://istlab.dmst.aueb.gr/~george - - - bkarak - Vassilios Karakoidas - vassilios.karakoidas@gmail.com - http://bkarak.wizhut.com/ - - + + + gousiosg + Georgios Gousios + gousiosg@gmail.com + http://istlab.dmst.aueb.gr/~george + + + bkarak + Vassilios Karakoidas + vassilios.karakoidas@gmail.com + http://bkarak.wizhut.com/ + + - - http://git.sqo-oss.org/ - scm:git:git://git.sqo-oss.org/sqo-oss.git - scm:git:ssh://git@git.sqo-oss.org:sqo-oss.git - + + http://git.sqo-oss.org/ + scm:git:git://git.sqo-oss.org/sqo-oss.git + scm:git:ssh://git@git.sqo-oss.org:sqo-oss.git + - - - - - org.apache.maven.plugins - maven-assembly-plugin - 2.3 - - - - - jar-with-dependencies - - - - - - org.ops4j - maven-pax-plugin - 1.4 - - equinox - - mvn:org.osgi/org.osgi.core/4.2.0@2 - mvn:org.osgi/org.osgi.compendium/4.2.0@2 - mvn:org.apache.felix/org.apache.felix.webconsole/1.2.8@2 - mvn:org.apache.felix/org.apache.felix.scr/1.0.8@2 - mvn:org.apache.felix/org.apache.felix.http.jetty/1.0.1@2 - mvn:org.apache.felix/org.apache.felix.eventadmin/1.0.0@2 - mvn:eu.sqooss.alitheia/core/0.95-SNAPSHOT@3 - - 1.5.0 - - - - org.apache.maven.plugins - maven-compiler-plugin - 2.3.2 - - true - true - 1.7 - 1.7 - - - - org.apache.maven.plugins - maven-release-plugin - 2.0 - - https://svn.sqo-oss.org/tags - - - - - - org.apache.maven.wagon - wagon-webdav - 1.0-beta-2 - - - - - - - - - org.apache.maven.plugins - maven-javadoc-plugin - 2.7 - - true - api - eu.sqooss.impl.* - - - - - - - - - skiptests - - true - - tests - 0 - - - + + - - org.apache.maven.plugins - maven-surefire-plugin - 2.7.1 - - true - - + + org.apache.maven.plugins + maven-assembly-plugin + 2.3 + + + + + jar-with-dependencies + + + + + + org.ops4j + maven-pax-plugin + 1.4 + + equinox + + mvn:org.osgi/org.osgi.core/4.2.0@2 + mvn:org.osgi/org.osgi.compendium/4.2.0@2 + mvn:org.apache.felix/org.apache.felix.webconsole/1.2.8@2 + mvn:org.apache.felix/org.apache.felix.scr/1.0.8@2 + mvn:org.apache.felix/org.apache.felix.http.jetty/1.0.1@2 + mvn:org.apache.felix/org.apache.felix.eventadmin/1.0.0@2 + mvn:eu.sqooss.alitheia/core/0.95-SNAPSHOT@3 + + 1.5.0 + + + + org.apache.maven.plugins + maven-compiler-plugin + 2.3.2 + + true + true + 1.7 + 1.7 + + + + org.apache.maven.plugins + maven-release-plugin + 2.0 + + https://svn.sqo-oss.org/tags + + - - - - runtests - - - tests - 1 - - - + + + org.apache.maven.wagon + wagon-webdav + 1.0-beta-2 + + + + + + - - org.apache.maven.plugins - maven-surefire-plugin - 2.7.1 - - false - - + + org.apache.maven.plugins + maven-javadoc-plugin + 2.7 + + true + api + eu.sqooss.impl.* + + - - - + + + + + + skiptests + + true + + tests + 0 + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.7.1 + + true + + + + + + + runtests + + + tests + 1 + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.7.1 + + false + + + + + + + + + org.jmockit + jmockit + 1.14 + test + +