diff --git a/run_neo4j.sh b/run_neo4j.sh new file mode 100755 index 0000000..5ab1530 --- /dev/null +++ b/run_neo4j.sh @@ -0,0 +1,11 @@ +#!/bin/sh + +docker stop neo4j +docker rm neo4j + +docker run -d \ + --publish=7474:7474 --publish=7687:7687 \ + --volume=$HOME/neo4j/data:/data \ + --volume=$HOME/neo4j/logs:/logs \ + --name neo4j \ + neo4j:3.1 diff --git a/src/main/java/org/wikitolearn/wikirating/controller/MaintenanceController.java b/src/main/java/org/wikitolearn/wikirating/controller/MaintenanceController.java index 0f08a60..cf00d11 100644 --- a/src/main/java/org/wikitolearn/wikirating/controller/MaintenanceController.java +++ b/src/main/java/org/wikitolearn/wikirating/controller/MaintenanceController.java @@ -1,199 +1,192 @@ /** * */ package org.wikitolearn.wikirating.controller; import java.io.File; import java.io.FileOutputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.List; import java.util.Properties; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import org.json.JSONException; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.util.DefaultPropertiesPersister; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.wikitolearn.wikirating.model.Process; import org.wikitolearn.wikirating.service.*; import org.wikitolearn.wikirating.util.enums.ProcessStatus; import org.wikitolearn.wikirating.util.enums.ProcessType; /** * * @author aletundo * */ @RestController public class MaintenanceController { private static final Logger LOG = LoggerFactory.getLogger(MaintenanceController.class); @Autowired private PageService pageService; @Autowired private UserService userService; @Autowired private RevisionService revisionService; @Autowired private ProcessService processService; @Autowired private MetadataService metadataService; @Value("#{'${mediawiki.langs}'.split(',')}") private List langs; @Value("${mediawiki.protocol}") private String protocol; @Value("${mediawiki.api.url}") private String apiUrl; /** * Secured endpoint to enable or disable read only mode. When read only mode * is enabled only GET requests are allowed. To change this behavior @see * org.wikitolearn.wikirating.wikirating.filter.MaintenanceFilter. * * @param active * String requested parameter that toggle the re. Binary values * are accepted. * @return a JSON object with the response */ @RequestMapping(value = "${maintenance.readonlymode.uri}", method = RequestMethod.POST, produces = "application/json") public String toggleReadOnlyMode(@RequestParam(value = "active") String active) { JSONObject response = new JSONObject(); int mode = Integer.parseInt(active); try { if (mode == 0) { response.put("status", "success"); response.put("message", "Application is live now."); // Delete maintenance lock file if it exists File f = new File("maintenance.lock"); if (f.exists()) { f.delete(); LOG.debug("Deleted maintenance lock file."); } LOG.info("Application is live now."); } else if (mode == 1) { try { response.put("status", "success"); response.put("message", "Application is in maintenance mode now."); // Create maintenance lock file with a maintenance.active // property setted to true Properties props = new Properties(); props.setProperty("maintenance.active", "true"); File lockFile = new File("maintenance.lock"); OutputStream out = new FileOutputStream(lockFile); DefaultPropertiesPersister p = new DefaultPropertiesPersister(); p.store(props, out, "Maintenance mode lock file"); LOG.debug("Created maintenance lock file."); LOG.info("Application is in maintenance mode now."); } catch (Exception e) { LOG.error("Something went wrong. {}", e.getMessage()); } } else { // The active parameter value is not supported response.put("status", "error"); response.put("message", "Parameter value not supported"); } } catch (JSONException e) { LOG.error("Something went wrong using JSON API. {}", e.getMessage()); } return response.toString(); } /** * Secured endpoint that handles initialization request for the given * language * * @return true if the initialization is completed without errors, false * otherwise */ @RequestMapping(value = "${maintenance.init.uri}", method = RequestMethod.POST, produces = "application/json") public boolean initialize() { // Initialize Metadata service metadataService.initMetadata(); // Starting a new Process Process initializeProcess = processService.createNewProcess(ProcessType.INIT); CompletableFuture initFuture = CompletableFuture .allOf(buildUsersAndPagesFutersList().toArray(new CompletableFuture[langs.size() + 1])) .thenCompose(result -> CompletableFuture .allOf(buildRevisionsFuturesList().toArray(new CompletableFuture[langs.size()]))) .thenCompose(result -> userService.setAllUsersAuthorship()); - /* - * CompletableFuture parallelInsertions = - * CompletableFuture.allOf(pageService.addAllPages(lang, url), - * userService.addAllUsers(url)) .thenCompose(result -> - * revisionService.addAllRevisions(lang, url)) .thenCompose(result -> - * userService.setAllUsersAuthorship()); - */ try { boolean result = initFuture.get(); //saving the result of the process if (result){ processService.closeCurrentProcess(ProcessStatus.DONE); }else{ processService.closeCurrentProcess(ProcessStatus.EXCEPTION); } return result; } catch (InterruptedException | ExecutionException e) { LOG.error("Something went wrong. {}", e.getMessage()); return false; } } /** * */ @RequestMapping(value = "${maintenance.wipe.uri}", method = RequestMethod.DELETE, produces = "application/json") public void wipeDatabase() { // TODO } /** * Build a list of CompletableFuture. The elements are the fetches of pages' * revisions from each domain language. * * @return a list of CompletableFuture */ private List> buildRevisionsFuturesList() { List> parallelRevisionsFutures = new ArrayList<>(); // Add revisions fetch for each domain language for (String lang : langs) { String url = protocol + lang + "." + apiUrl; parallelRevisionsFutures.add(revisionService.addAllRevisions(lang, url)); } return parallelRevisionsFutures; } /** * Build a list of CompletableFuture. The first one is the fetch of the * users from the first domain in mediawiki.langs list. The rest of the * elements are the fetches of the pages for each language. This * implementation assumes that the users are shared among domains. * * @return a list of CompletableFuture */ private List> buildUsersAndPagesFutersList() { List> usersAndPagesInsertion = new ArrayList<>(); // Add users fetch as fist operation usersAndPagesInsertion.add(userService.addAllUsers(protocol + langs.get(0) + "." + apiUrl)); // Add pages fetch for each domain language for (String lang : langs) { String url = protocol + lang + "." + apiUrl; usersAndPagesInsertion.add(pageService.addAllPages(lang, url)); } return usersAndPagesInsertion; } } diff --git a/src/main/java/org/wikitolearn/wikirating/model/Page.java b/src/main/java/org/wikitolearn/wikirating/model/Page.java index d1df2ec..03936cc 100644 --- a/src/main/java/org/wikitolearn/wikirating/model/Page.java +++ b/src/main/java/org/wikitolearn/wikirating/model/Page.java @@ -1,152 +1,153 @@ /** * */ package org.wikitolearn.wikirating.model; import org.neo4j.ogm.annotation.GraphId; import org.neo4j.ogm.annotation.Index; import org.neo4j.ogm.annotation.NodeEntity; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import org.neo4j.ogm.annotation.Relationship; /** * * @author aletundo, valsdav * */ @JsonIgnoreProperties(ignoreUnknown = true) @NodeEntity( label = "Page") public class Page { @GraphId private Long graphId; private int pageid; private String title; + @Index private String lang; @Index(unique = true, primary=true) private String langPageId; private double pageRank; @Relationship(type = "LAST_REVISION", direction = Relationship.OUTGOING) private Revision lastRevision; @Relationship(type = "FIRST_REVISION", direction= Relationship.OUTGOING) private Revision fistRevision; /** * */ public Page() { } /** * @param title * @param pageid * @param pageRank */ public Page(String title, int pageid, double pageRank) { this.title = title; this.pageid = pageid; this.pageRank = pageRank; } /** * @return the title */ public String getTitle() { return title; } /** * @param title the title to set */ public void setTitle(String title) { this.title = title; } /** * @return the pageid */ public int getPageid() { return pageid; } /** * @param pageid the pageid to set */ public void setPageid(int pageid) { this.pageid = pageid; } /** * @return the pageRank */ public double getPageRank() { return pageRank; } /** * @param pageRank the pageRank to set */ public void setPageRank(double pageRank) { this.pageRank = pageRank; } /** * @return the lang */ public String getLang() { return lang; } /** * @param lang the lang to set */ public void setLang(String lang) { this.lang = lang; } /** * @return the langPageId */ public String getLangPageId() { return langPageId; } /** * @param langPageId the langPageId to set */ public void setLangPageId(String langPageId) { this.langPageId = langPageId; } /** * * @return */ public Revision getLastRevision() { return lastRevision; } /** * * @param lastRevision */ public void setLastRevision(Revision lastRevision) { this.lastRevision = lastRevision; } /** * * @return */ public Revision getFistRevision() { return fistRevision; } /** * * @param fistRevision */ public void setFistRevision(Revision fistRevision) { this.fistRevision = fistRevision; } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { return "Page [title=" + title + ", pageid=" + pageid + ", pageRank=" + pageRank + "]"; } } diff --git a/src/main/java/org/wikitolearn/wikirating/repository/ProcessRepository.java b/src/main/java/org/wikitolearn/wikirating/repository/ProcessRepository.java index e99ca09..1963c80 100644 --- a/src/main/java/org/wikitolearn/wikirating/repository/ProcessRepository.java +++ b/src/main/java/org/wikitolearn/wikirating/repository/ProcessRepository.java @@ -1,19 +1,27 @@ /** * */ package org.wikitolearn.wikirating.repository; import org.springframework.data.neo4j.annotation.Query; import org.springframework.data.neo4j.repository.GraphRepository; import org.wikitolearn.wikirating.model.Process; import org.wikitolearn.wikirating.util.enums.MetadataType; +import java.util.Date; + /** * @author aletundo * */ public interface ProcessRepository extends GraphRepository { + /** + * This query returns the last process created: the one connected to the + * Metadata node of PROCESSES type. + * @return + */ @Query("MATCH (p:Process)<-[LAST_PROCESS]-(m:Metadata {type:'PROCESSES'}) RETURN p") public Process getLastProcess(); + } diff --git a/src/main/java/org/wikitolearn/wikirating/service/MetadataService.java b/src/main/java/org/wikitolearn/wikirating/service/MetadataService.java index 451f0b3..5bddbd7 100644 --- a/src/main/java/org/wikitolearn/wikirating/service/MetadataService.java +++ b/src/main/java/org/wikitolearn/wikirating/service/MetadataService.java @@ -1,44 +1,53 @@ package org.wikitolearn.wikirating.service; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.wikitolearn.wikirating.model.Metadata; import org.wikitolearn.wikirating.model.Process; import org.wikitolearn.wikirating.repository.MetadataRepository; import org.wikitolearn.wikirating.repository.ProcessRepository; import org.wikitolearn.wikirating.service.mediawiki.PageMediaWikiService; import org.wikitolearn.wikirating.util.enums.MetadataType; /** * This service manages the addition of information about Metadata. * Created by valsdav on 29/03/17. */ @Service public class MetadataService { private static final Logger LOG = LoggerFactory.getLogger(PageService.class); @Autowired private PageMediaWikiService pageMediaWikiService; @Autowired private MetadataRepository metadataRepository; @Autowired private ProcessRepository processRepository; + /** + * This method insert in the DB the root nodes of the metadata + */ public void initMetadata(){ Metadata metadataProcesses = new Metadata(MetadataType.PROCESSES); Metadata metadataStats = new Metadata(MetadataType.STATS); metadataRepository.save(metadataProcesses); metadataRepository.save(metadataStats); } + /** + * This method inserts in the DB a new Process connecting it + * to the Metadata root node and to the previous Process. + * @param process + * @return + */ public boolean addProcess(Process process){ Metadata metadata = metadataRepository.getMetadataByType(MetadataType.PROCESSES); //Creating the new process node of the chain process.setPreviousProcess(metadata.getLastItem()); metadata.setLastItem(process); metadataRepository.save(metadata); LOG.info("Process {} inserted ", process); return true; } } diff --git a/src/main/java/org/wikitolearn/wikirating/service/ProcessService.java b/src/main/java/org/wikitolearn/wikirating/service/ProcessService.java index 4ad3bf0..9e6ded9 100644 --- a/src/main/java/org/wikitolearn/wikirating/service/ProcessService.java +++ b/src/main/java/org/wikitolearn/wikirating/service/ProcessService.java @@ -1,37 +1,49 @@ package org.wikitolearn.wikirating.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.wikitolearn.wikirating.model.Process; import org.wikitolearn.wikirating.repository.ProcessRepository; import org.wikitolearn.wikirating.util.enums.ProcessStatus; import org.wikitolearn.wikirating.util.enums.ProcessType; import java.util.Date; /** * Created by valsdav on 29/03/17. */ @Service public class ProcessService { @Autowired private MetadataService metadataService; @Autowired private ProcessRepository processRepository; + /** + * This method creates a new process of the specified + * type and adds it on the top of the processes chain. + * @param type Type of process requested + * @return returns the created process + */ public Process createNewProcess(ProcessType type){ Process proc = new Process(type); metadataService.addProcess(proc); processRepository.save(proc); return proc; } + /** + * This method modify the status of the last opened process + * and saves it. + * @param status Final status of the process + * @return returns the closed process + */ public Process closeCurrentProcess(ProcessStatus status){ Process currentProcess = processRepository.getLastProcess(); currentProcess.setProcessStatus(status); currentProcess.setEndOfProcess(new Date()); processRepository.save(currentProcess); return currentProcess; } }