diff --git a/docker/Dockerfile b/docker/Dockerfile index 4259dcf87ead2ef2104dc508a6281bd158cf8370..00efdade78173a9e86a0116e86db20cc2a8f62e4 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -20,5 +20,5 @@ COPY elasticsearch.yml /elasticsearch/config/elasticsearch.yml COPY nginx.conf /etc/nginx/nginx.conf COPY webapps /tomcat/webapps/ COPY webroot /webroot/ -EXPOSE 80 9300 27017 +EXPOSE 80 6789 9300 27017 CMD ["/usr/bin/supervisord"] \ No newline at end of file diff --git a/docker/docker-run.sh b/docker/docker-run.sh index c77b960862a3bdfd76a88f7f1062811b3535c0a2..cc06ef3567f07b0569ac3297bb86f303d2435546 100755 --- a/docker/docker-run.sh +++ b/docker/docker-run.sh @@ -5,6 +5,7 @@ # set host machine ports HOST_NGINX=80 +HOST_IPC=6789 HOST_ELASTICSEARCH_API=9300 HOST_MONGODB=27017 @@ -15,7 +16,7 @@ REPLACE_WEBROOT=1 ####################################################################################### DIR="$(dirname "$(readlink -f "$0")")" -PORT_MAPPING="-p $HOST_NGINX:80 -p $HOST_ELASTICSEARCH_API:9300 -p $HOST_MONGODB:27017" +PORT_MAPPING="-p $HOST_NGINX:80 -p $HOST_IPC:6789 -p $HOST_ELASTICSEARCH_API:9300 -p $HOST_MONGODB:27017" if [ $REPLACE_WEBAPPS -eq 1 ]; then VOLUME_WEBAPPS="-v $DIR/webapps:/tomcat/webapps" diff --git a/docker/nginx.conf b/docker/nginx.conf index 9cae4d2869893a1b36e390256cc1196036b6d329..a76a421d0feb0fd4d9f90fd28af39a72d5726bf2 100644 --- a/docker/nginx.conf +++ b/docker/nginx.conf @@ -20,13 +20,14 @@ http { error_log /var/log/nginx/error.log; gzip on; + gzip_static on; gzip_disable "msie6"; gzip_vary on; gzip_proxied any; gzip_comp_level 6; gzip_buffers 16 8k; gzip_http_version 1.1; - gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript; + gzip_types text/plain text/css application/json application/x-javascript text/xml application/xml application/rss+xml text/javascript image/svg+xml application/vnd.ms-fontobject application/x-font-ttf font/opentype; server { listen 80 default; @@ -42,7 +43,18 @@ http { proxy_buffering off; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://localhost:8080/rest/; } + + location /ws { + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_pass http://localhost:8080/ws; + } } } \ No newline at end of file diff --git a/make-release.sh b/make-release.sh index 2d85f1f62fd75a31c8bcd8ffac6857d4b6fc9ea6..bd344450faa2d8d8a939ab384df8f57e1f5fa948 100755 --- a/make-release.sh +++ b/make-release.sh @@ -14,7 +14,7 @@ DIR="$(dirname "$(readlink -f "$0")")" REL_NAME="vipra-$VERSION" REL="$DIR/$REL_NAME" -rm -rf $REL $REL.tar.gz +rm -rf $REL vipra*.tar.gz mkdir -p $REL/vipra-backend $REL/vipra-cmd $REL/vipra-ui cp -r $DIR/dtm_release $REL/dtm_release find $REL -type f -name "*.o" -exec rm -f {} \; @@ -24,6 +24,7 @@ cp $DIR/vipra-cmd/target/*.jar $REL/vipra-cmd/vipra.jar cp -r $DIR/vipra-cmd/target/lib $REL/vipra-cmd/lib cp -r $DIR/vipra-ui/public $REL/vipra-ui cp $DIR/vipra $REL/vipra-cmd/vipra +cp $DIR/vipra $REL/vipra cp $DIR/LICENSE $DIR/README.md $REL cp $DIR/scripts/* $REL diff --git a/scripts/install.sh b/scripts/install.sh old mode 100644 new mode 100755 index cc1f786e84631faabc68d86a3aefffbd1ae03a06..092a48ac3fcae74db4ddab447814853cbb42e2be --- a/scripts/install.sh +++ b/scripts/install.sh @@ -1 +1,16 @@ -#!/bin/bash \ No newline at end of file +#!/bin/bash + +DIR="$(dirname "$(readlink -f "$0")")" + +cd $DIR + +sudo rm -rf /opt/vipra +sudo mkdir -p /opt/vipra +sudo cp -r ./* /opt/vipra/ +sudo ln -sf /opt/vipra/vipra /bin/vipra + +cd $OLDPWD + +echo "vipra installed to /opt/vipra" +echo "use 'vipra' command to access vipra, test system with 'vipra -t'" +echo "REQUIRED: install libgsl-dev and manually compile dtm: 'sudo make -C /opt/vipra/dtm_release/dtm'" \ No newline at end of file diff --git a/scripts/uninstall.sh b/scripts/uninstall.sh old mode 100644 new mode 100755 index cc1f786e84631faabc68d86a3aefffbd1ae03a06..50c945636aa263558aef8a41bc30c060bc9dd739 --- a/scripts/uninstall.sh +++ b/scripts/uninstall.sh @@ -1 +1,6 @@ -#!/bin/bash \ No newline at end of file +#!/bin/bash + +sudo rm -rf /opt/vipra +sudo rm /bin/vipra +rm -rf $HOME/.config/vipra +rm -rf $HOME/.local/share/vipra \ No newline at end of file diff --git a/vipra b/vipra index eb76199dd4bdbd26fb745d844eb3c1a1524e1613..f41c26c7ddbaa43841379c36841608374fbbefd9 100755 --- a/vipra +++ b/vipra @@ -10,11 +10,16 @@ if [ $? -ne 0 ]; then fi JARS="$VIPRA_JAR -/opt/vipra/vipra-cmd/target/vipra*.jar -vipra*.jar +$VIPRA_HOME/vipra-cmd/vipra*.jar +$VIPRA_HOME/vipra-cmd/target/vipra*.jar +$VIPRA_HOME/target/vipra*.jar +$VIPRA_HOME/vipra*.jar +$DIR/vipra-cmd/vipra*.jar $DIR/vipra-cmd/target/vipra*.jar $DIR/target/vipra*.jar -$DIR/vipra*.jar" +$DIR/vipra*.jar +/opt/vipra/vipra-cmd/target/vipra*.jar +vipra*.jar" for f in $JARS do if [ -f $f ]; then diff --git a/vipra-backend/src/main/java/de/vipra/rest/Application.java b/vipra-backend/src/main/java/de/vipra/rest/Application.java index eb1e7649e367c8dbe4ae8a98f5fce85c8f7f20ae..1af81e485178f0114eb72dbb2ffc095f63479a0a 100644 --- a/vipra-backend/src/main/java/de/vipra/rest/Application.java +++ b/vipra-backend/src/main/java/de/vipra/rest/Application.java @@ -11,6 +11,7 @@ import de.vipra.rest.provider.ObjectMapperProvider; public class Application extends ResourceConfig { public Application() { + // register rest application packages("de.vipra.rest.resource"); register(JacksonFeature.class); register(CORSResponseFilter.class); diff --git a/vipra-backend/src/main/java/de/vipra/rest/provider/RestServletContextListener.java b/vipra-backend/src/main/java/de/vipra/rest/provider/RestServletContextListener.java new file mode 100644 index 0000000000000000000000000000000000000000..9f932b398e728f9c6e912c5fbbd109b0ecbf4be0 --- /dev/null +++ b/vipra-backend/src/main/java/de/vipra/rest/provider/RestServletContextListener.java @@ -0,0 +1,27 @@ +package de.vipra.rest.provider; + +import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import de.vipra.util.IPCServer; +import de.vipra.ws.WebSocketChain; + +public class RestServletContextListener implements ServletContextListener { + + public static final Logger log = LogManager.getLogger(RestServletContextListener.class); + + @Override + public void contextDestroyed(final ServletContextEvent arg0) {} + + @Override + public void contextInitialized(final ServletContextEvent arg0) { + final IPCServer ipcServer = IPCServer.getInstance(); + ipcServer.register("websocket", new WebSocketChain()); + ipcServer.start(); + log.info("started ipc server"); + } + +} diff --git a/vipra-backend/src/main/java/de/vipra/ws/WebSocket.java b/vipra-backend/src/main/java/de/vipra/ws/WebSocket.java new file mode 100644 index 0000000000000000000000000000000000000000..7e31d080e228911d0fb368d58f95b1a84a0db255 --- /dev/null +++ b/vipra-backend/src/main/java/de/vipra/ws/WebSocket.java @@ -0,0 +1,61 @@ +package de.vipra.ws; + +import java.io.IOException; +import java.util.HashSet; +import java.util.Set; + +import javax.websocket.OnClose; +import javax.websocket.OnError; +import javax.websocket.OnMessage; +import javax.websocket.OnOpen; +import javax.websocket.Session; +import javax.websocket.server.ServerEndpoint; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonMappingException; + +import de.vipra.util.Config; +import de.vipra.util.IPCMessage; + +@ServerEndpoint("/ws") +public class WebSocket { + + public static final Logger log = LogManager.getLogger(WebSocket.class); + + private static final Set<Session> sessions = new HashSet<>(); + + @OnOpen + public void open(final Session session) { + sessions.add(session); + } + + @OnClose + public void close(final Session session) { + sessions.remove(session); + } + + @OnError + public void onError(final Throwable error) { + log.error(error); + } + + @OnMessage + public void handleMessage(final String input, final Session session) throws JsonParseException, JsonMappingException, IOException {} + + public static void sendMessage(final IPCMessage message) throws JsonProcessingException { + sendMessage(Config.mapper.writeValueAsString(message)); + } + + public static void sendMessage(final String message) { + for (final Session session : sessions) + if (session.isOpen()) + session.getAsyncRemote().sendText(message); + else + sessions.remove(session); + } + +} diff --git a/vipra-backend/src/main/java/de/vipra/ws/WebSocketChain.java b/vipra-backend/src/main/java/de/vipra/ws/WebSocketChain.java new file mode 100644 index 0000000000000000000000000000000000000000..a8efcaf286a84c4f56da3154852663f6ec3fa14e --- /dev/null +++ b/vipra-backend/src/main/java/de/vipra/ws/WebSocketChain.java @@ -0,0 +1,31 @@ +package de.vipra.ws; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import com.fasterxml.jackson.core.JsonProcessingException; + +import de.vipra.util.IPCChain; +import de.vipra.util.IPCMessage; + +public class WebSocketChain implements IPCChain { + + public static final Logger log = LogManager.getLogger(WebSocketChain.class); + + @Override + public void call(final IPCMessage message) { + switch (message.getCode()) { + case MESSAGE: + WebSocket.sendMessage(message.getMessage()); + break; + default: + try { + WebSocket.sendMessage(message); + } catch (final JsonProcessingException e) { + log.error(e); + } + break; + } + } + +} diff --git a/vipra-backend/src/main/resources/config.json b/vipra-backend/src/main/resources/config.json index b5a9ad2919414e3006df5a8acbbfeeeee475bf8b..dbea69e69826ba341db53d9cf1fa7fc15522c0ec 100644 --- a/vipra-backend/src/main/resources/config.json +++ b/vipra-backend/src/main/resources/config.json @@ -3,5 +3,7 @@ "databasePort": 27017, "databaseName": "test", "elasticSearchHost": "127.0.0.1", - "elasticSearchPort": 9300 + "elasticSearchPort": 9300, + "ipcHost": "127.0.0.1", + "ipcPort": 6789 } \ No newline at end of file diff --git a/vipra-backend/src/main/webapp/WEB-INF/web.xml b/vipra-backend/src/main/webapp/WEB-INF/web.xml index da89b35de944060a099ff17a206f8e391abc82c3..889bf7934570d306415b8a1d100d0ecbd0d755e6 100644 --- a/vipra-backend/src/main/webapp/WEB-INF/web.xml +++ b/vipra-backend/src/main/webapp/WEB-INF/web.xml @@ -15,4 +15,9 @@ <servlet-name>jersey</servlet-name> <url-pattern>/rest/*</url-pattern> </servlet-mapping> + <listener> + <listener-class> + de.vipra.rest.provider.RestServletContextListener + </listener-class> + </listener> </web-app> \ No newline at end of file diff --git a/vipra-cmd/runcfg/CMD.launch b/vipra-cmd/runcfg/CMD.launch index 3f9ca734b340ba4c09c275021439c0ee8e184b7c..b36db2e1f99f6ae77ceb1a8501b802a2a37c5e24 100644 --- a/vipra-cmd/runcfg/CMD.launch +++ b/vipra-cmd/runcfg/CMD.launch @@ -11,7 +11,7 @@ </listAttribute> <stringAttribute key="org.eclipse.jdt.launching.CLASSPATH_PROVIDER" value="org.eclipse.m2e.launchconfig.classpathProvider"/> <stringAttribute key="org.eclipse.jdt.launching.MAIN_TYPE" value="de.vipra.cmd.Main"/> -<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-D test"/> +<stringAttribute key="org.eclipse.jdt.launching.PROGRAM_ARGUMENTS" value="-t"/> <stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="vipra-cmd"/> <stringAttribute key="org.eclipse.jdt.launching.SOURCE_PATH_PROVIDER" value="org.eclipse.m2e.launchconfig.sourcepathProvider"/> <stringAttribute key="org.eclipse.jdt.launching.VM_ARGUMENTS" value="-ea"/> diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/CommandLineOptions.java b/vipra-cmd/src/main/java/de/vipra/cmd/CommandLineOptions.java index 4ce7824862b41f916a378c2c92f9b642ddf621f1..45e3b4adc920a1cb54094c2f882fbe0ae19275ec 100644 --- a/vipra-cmd/src/main/java/de/vipra/cmd/CommandLineOptions.java +++ b/vipra-cmd/src/main/java/de/vipra/cmd/CommandLineOptions.java @@ -37,6 +37,7 @@ public class CommandLineOptions { public static final Option MODEL = Option.builder("M").longOpt("model").desc("generate topics on models").hasArgs().argName("[models...]") .optionalArg(true).build(); public static final Option SELECT = Option.builder("S").longOpt("select").desc("select models").hasArgs().argName("models...").build(); + public static final Option MESSAGE = Option.builder("m").longOpt("message").desc("send a global message").hasArg().argName("message").build(); private final Options options; private CommandLine cmd; @@ -44,7 +45,7 @@ public class CommandLineOptions { public CommandLineOptions() { final Option[] optionsArray = { CLEAR, DEBUG, HELP, INDEX, LIST, REREAD, SILENT, TEST, ALL, CREATE, DELETE, EDIT, PRINT, IMPORT, MODEL, - SELECT }; + SELECT, MESSAGE }; options = new Options(); for (final Option option : optionsArray) options.addOption(option); @@ -56,9 +57,9 @@ public class CommandLineOptions { private String[] split(final String[] args) { final List<String> args2 = new ArrayList<>(); - for (String arg : args) { + for (final String arg : args) { if (arg.startsWith("-") && arg.length() > 2) { - for (char c : arg.substring(1, arg.length()).toCharArray()) + for (final char c : arg.substring(1, arg.length()).toCharArray()) args2.add("-" + c); } else { args2.add(arg); @@ -217,4 +218,12 @@ public class CommandLineOptions { throw new RuntimeException("select at least one model"); } + public boolean isMessage() { + return hasOption(MESSAGE); + } + + public String messageToSend() { + return getOptionValue(MESSAGE); + } + } diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/ErrorCodes.java b/vipra-cmd/src/main/java/de/vipra/cmd/ErrorCodes.java new file mode 100644 index 0000000000000000000000000000000000000000..893b6bd5ef3444b8d23880e0da8bf41d75a6ed88 --- /dev/null +++ b/vipra-cmd/src/main/java/de/vipra/cmd/ErrorCodes.java @@ -0,0 +1,7 @@ +package de.vipra.cmd; + +public enum ErrorCodes { + NONE, + CANNOT_LOCK, + CANNOT_UNLOCK +} diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/Main.java b/vipra-cmd/src/main/java/de/vipra/cmd/Main.java index e6cb162db1b4ece5987e89c931e5f67844825743..8c8d894f8d1a24438a879975a7a4af537ba8e69b 100644 --- a/vipra-cmd/src/main/java/de/vipra/cmd/Main.java +++ b/vipra-cmd/src/main/java/de/vipra/cmd/Main.java @@ -1,6 +1,5 @@ package de.vipra.cmd; -import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.ListIterator; @@ -16,22 +15,46 @@ import de.vipra.cmd.option.EditModelCommand; import de.vipra.cmd.option.ImportCommand; import de.vipra.cmd.option.IndexingCommand; import de.vipra.cmd.option.ListModelsCommand; +import de.vipra.cmd.option.MessageCommand; import de.vipra.cmd.option.ModelingCommand; import de.vipra.cmd.option.PrintModelCommand; import de.vipra.cmd.option.TestCommand; import de.vipra.util.ConsoleUtils; -import de.vipra.util.ex.ConfigException; +import de.vipra.util.LockFile; +import de.vipra.util.ex.LockFileException; public class Main { + private static final LockFile lockFile = new LockFile(); + static { // set morphia log level MorphiaLoggerFactory.registerLogger(SLF4JLoggerImplFactory.class); + // set corenlp log level, close stderr to mute corenlp messages System.err.close(); + + } + + private static void lock() { + try { + lockFile.lock(); + } catch (final LockFileException e1) { + ConsoleUtils.error("Cannot acquire lock. Is vipra already running? If not, delete the file '" + lockFile.getPath() + "'"); + System.exit(ErrorCodes.CANNOT_LOCK.ordinal()); + } } - public static void main(final String[] args) throws IOException, ConfigException { + private static void unlock() { + try { + lockFile.unlock(); + } catch (final LockFileException e) { + ConsoleUtils.error("Cannot delete lock file. Delete the file '" + lockFile.getPath() + "'"); + System.exit(ErrorCodes.CANNOT_UNLOCK.ordinal()); + } + } + + private static void execute(final String[] args) { final CommandLineOptions opts = new CommandLineOptions(); try { opts.parse(args); @@ -57,6 +80,9 @@ public class Main { if (opts.isTest()) commands.add(new TestCommand()); + if (opts.isMessage()) + commands.add(new MessageCommand(opts.messageToSend())); + if (opts.isClear()) commands.add(new ClearCommand()); @@ -106,4 +132,10 @@ public class Main { } } + public static void main(final String[] args) { + lock(); + execute(args); + unlock(); + } + } diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/lda/Analyzer.java b/vipra-cmd/src/main/java/de/vipra/cmd/lda/Analyzer.java index 8bbdec95453a37b7fbbbadd4c1cce7bd8a9f4761..f7fd26ca3c72b076baf4b55b12abf9b57aa7ebcc 100644 --- a/vipra-cmd/src/main/java/de/vipra/cmd/lda/Analyzer.java +++ b/vipra-cmd/src/main/java/de/vipra/cmd/lda/Analyzer.java @@ -373,7 +373,7 @@ public class Analyzer { reducedShare += topicDistribution[idxTopic]; final TopicShare newTopicRef = new TopicShare(); final TopicFull topicFull = newTopics.get(idxTopic); - Integer articlesCount = topicFull.getArticlesCount(); + final Integer articlesCount = topicFull.getArticlesCount(); topicFull.setArticlesCount(articlesCount == null ? 1 : articlesCount + 1); newTopicRef.setTopic(new Topic(topicFull.getId())); newTopicRef.setShare(topicDistribution[idxTopic]); @@ -436,22 +436,22 @@ public class Analyzer { // remove unreferenced topics - for (ListIterator<TopicFull> iter = newTopics.listIterator(); iter.hasNext();) { - TopicFull topic = iter.next(); - Integer articlesCount = topic.getArticlesCount(); + for (final ListIterator<TopicFull> iter = newTopics.listIterator(); iter.hasNext();) { + final TopicFull topic = iter.next(); + final Integer articlesCount = topic.getArticlesCount(); if (articlesCount == null || articlesCount == 0) iter.remove(); } // calculate topic similarities - int topicMinCount = (int) Math.ceil(topicCount * (1 - modelConfig.getMaxSimilarTopicsDivergence())); + final int topicMinCount = (int) Math.ceil(topicCount * (1 - modelConfig.getMaxSimilarTopicsDivergence())); - for (TopicFull topic1 : newTopics) { + for (final TopicFull topic1 : newTopics) { final List<TopicShare> similarTopics = new ArrayList<>(); - for (TopicFull topic2 : newTopics) { + for (final TopicFull topic2 : newTopics) { if (!topic1.getId().equals(topic2.getId())) { - Integer count = topicShareMatrix.get(topic1.getId(), topic2.getId()); + final Integer count = topicShareMatrix.get(topic1.getId(), topic2.getId()); if (count != null && count >= topicMinCount) { final TopicShare newTopicShare = new TopicShare(); newTopicShare.setTopic(new Topic(topic2.getId())); diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/option/ImportCommand.java b/vipra-cmd/src/main/java/de/vipra/cmd/option/ImportCommand.java index 53f1ac3aab41d39f63b1b0d7ea9b1372efb73f9d..92b2636e6901e8f9a19e3ad615a6aa905e08ad4d 100644 --- a/vipra-cmd/src/main/java/de/vipra/cmd/option/ImportCommand.java +++ b/vipra-cmd/src/main/java/de/vipra/cmd/option/ImportCommand.java @@ -31,6 +31,9 @@ import de.vipra.util.Config; import de.vipra.util.ConsoleUtils; import de.vipra.util.Constants; import de.vipra.util.Constants.ProcessorMode; +import de.vipra.util.IPCClient; +import de.vipra.util.IPCMessage; +import de.vipra.util.IPCMessageCode; import de.vipra.util.StringUtils; import de.vipra.util.Timer; import de.vipra.util.ex.ConfigException; @@ -344,9 +347,13 @@ public class ImportCommand implements Command { dbWords = MongoService.getDatabaseService(config, WordFull.class); dbWindows = MongoService.getDatabaseService(config, WindowFull.class); processor = new Processor(); + final IPCClient ipcClient = new IPCClient(); for (final TopicModelConfig modelConfig : config.getTopicModelConfigs(models)) { + ipcClient.send(new IPCMessage(IPCMessageCode.START_IMPORTING).message("Started importing for model '" + modelConfig.getName() + "'")); importForModel(modelConfig); + ipcClient.send(new IPCMessage(IPCMessageCode.STOP_IMPORTING).message("Finished importing for model '" + modelConfig.getName() + "'")); } + ipcClient.close(); } } \ No newline at end of file diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/option/IndexingCommand.java b/vipra-cmd/src/main/java/de/vipra/cmd/option/IndexingCommand.java index 112c38f759354ad0910f51fd4d6299863cbc82ba..f2792a843c1d708a7ac0eaf518184aafaa4d4b92 100644 --- a/vipra-cmd/src/main/java/de/vipra/cmd/option/IndexingCommand.java +++ b/vipra-cmd/src/main/java/de/vipra/cmd/option/IndexingCommand.java @@ -15,6 +15,9 @@ import de.vipra.util.Config; import de.vipra.util.ConsoleUtils; import de.vipra.util.ESClient; import de.vipra.util.ESSerializer; +import de.vipra.util.IPCClient; +import de.vipra.util.IPCMessage; +import de.vipra.util.IPCMessageCode; import de.vipra.util.MongoUtils; import de.vipra.util.StringUtils; import de.vipra.util.Timer; @@ -91,9 +94,13 @@ public class IndexingCommand implements Command { dbArticles = MongoService.getDatabaseService(config, ArticleFull.class); elasticClient = ESClient.getClient(config); elasticSerializer = new ESSerializer<>(ArticleFull.class); + final IPCClient ipcClient = new IPCClient(); for (final TopicModelConfig modelConfig : config.getTopicModelConfigs(models)) { + ipcClient.send(new IPCMessage(IPCMessageCode.START_INDEXING).message("Started indexing model '" + modelConfig.getName() + "'")); indexForModel(modelConfig); + ipcClient.send(new IPCMessage(IPCMessageCode.STOP_INDEXING).message("Finished indexing model '" + modelConfig.getName() + "'")); } + ipcClient.close(); } } diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/option/MessageCommand.java b/vipra-cmd/src/main/java/de/vipra/cmd/option/MessageCommand.java new file mode 100644 index 0000000000000000000000000000000000000000..2eba9b2425a84a92427e67a3e31870b829dd02e3 --- /dev/null +++ b/vipra-cmd/src/main/java/de/vipra/cmd/option/MessageCommand.java @@ -0,0 +1,22 @@ +package de.vipra.cmd.option; + +import de.vipra.util.IPCClient; +import de.vipra.util.IPCMessage; +import de.vipra.util.IPCMessageCode; + +public class MessageCommand implements Command { + + private final String message; + + public MessageCommand(final String message) { + this.message = message; + } + + @Override + public void run() throws Exception { + final IPCClient client = new IPCClient(); + client.send(new IPCMessage(IPCMessageCode.MESSAGE).message(message)); + client.close(); + } + +} diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/option/ModelingCommand.java b/vipra-cmd/src/main/java/de/vipra/cmd/option/ModelingCommand.java index 7ab98e13e075f2fa96de884402f4feeb433ad4ad..3bf6fa11dbb5cad03fe5b6275182dd8226857011 100644 --- a/vipra-cmd/src/main/java/de/vipra/cmd/option/ModelingCommand.java +++ b/vipra-cmd/src/main/java/de/vipra/cmd/option/ModelingCommand.java @@ -7,6 +7,9 @@ import de.vipra.cmd.lda.Analyzer; import de.vipra.cmd.lda.AnalyzerException; import de.vipra.util.Config; import de.vipra.util.ConsoleUtils; +import de.vipra.util.IPCClient; +import de.vipra.util.IPCMessage; +import de.vipra.util.IPCMessageCode; import de.vipra.util.StringUtils; import de.vipra.util.Timer; import de.vipra.util.ex.ConfigException; @@ -51,9 +54,13 @@ public class ModelingCommand implements Command { @Override public void run() throws Exception { final Config config = Config.getConfig(); + final IPCClient ipcClient = new IPCClient(); for (final TopicModelConfig modelConfig : config.getTopicModelConfigs(models)) { + ipcClient.send(new IPCMessage(IPCMessageCode.START_MODELING).message("Started generating model '" + modelConfig.getName() + "'")); modelForModel(modelConfig); + ipcClient.send(new IPCMessage(IPCMessageCode.STOP_MODELING).message("Finished generating model '" + modelConfig.getName() + "'")); } + ipcClient.close(); } } diff --git a/vipra-cmd/src/main/java/de/vipra/cmd/option/TestCommand.java b/vipra-cmd/src/main/java/de/vipra/cmd/option/TestCommand.java index 38a8b374d0c24fc291cfd8e52eaa4ac24ff0e020..d3d51d54a6c927a62741ca13a1a947c345af3852 100644 --- a/vipra-cmd/src/main/java/de/vipra/cmd/option/TestCommand.java +++ b/vipra-cmd/src/main/java/de/vipra/cmd/option/TestCommand.java @@ -1,12 +1,22 @@ package de.vipra.cmd.option; +import java.io.File; +import java.io.FileNotFoundException; +import java.net.HttpURLConnection; +import java.net.URL; + import org.bson.types.ObjectId; import org.elasticsearch.client.transport.NoNodeAvailableException; import org.elasticsearch.client.transport.TransportClient; +import org.fusesource.jansi.Ansi; +import org.fusesource.jansi.Ansi.Color; import de.vipra.util.Config; import de.vipra.util.ConsoleUtils; import de.vipra.util.ESClient; +import de.vipra.util.IPCClient; +import de.vipra.util.IPCMessage; +import de.vipra.util.IPCMessageCode; import de.vipra.util.model.Article; import de.vipra.util.service.MongoService; @@ -14,23 +24,57 @@ public class TestCommand implements Command { @Override public void run() throws Exception { - // test if configuration readable - ConsoleUtils.info("reading configuration..."); - final Config config = Config.getConfig(); - - // test if database is accessible - ConsoleUtils.info("testing mongodb connection..."); - final MongoService<Article, ObjectId> dbArticles = MongoService.getDatabaseService(config, Article.class); - dbArticles.count(null); - - // test if elasticsearch is accessible - ConsoleUtils.info("testing elasticsearch connection..."); - final TransportClient esclient = ESClient.getClient(config); - if (esclient.connectedNodes().isEmpty()) { - throw new NoNodeAvailableException("no elasticsearch nodes available"); - } + try { + // test if configuration readable + ConsoleUtils.infoNOLF("reading configuration..."); + final Config config = Config.getConfig(true); + ConsoleUtils.print(Ansi.ansi().fg(Color.GREEN).a("OK").reset().toString()); + + // test if dtm is accessible + ConsoleUtils.infoNOLF("testing dtm binary..."); + if (config.getDtmPath() == null || config.getDtmPath().isEmpty()) + throw new Exception("dtm binary not configured, set 'dtmPath' in config.json"); + final File dtm = new File(config.getDtmPath()); + if (!dtm.exists()) + throw new FileNotFoundException("dtm binary not available at path: '" + config.getDtmPath() + "'"); + ConsoleUtils.print(Ansi.ansi().fg(Color.GREEN).a("OK").reset().toString()); + + // test if database is accessible + ConsoleUtils.infoNOLF("testing mongodb connection..."); + final MongoService<Article, ObjectId> dbArticles = MongoService.getDatabaseService(config, Article.class); + dbArticles.count(null); + ConsoleUtils.print(Ansi.ansi().fg(Color.GREEN).a("OK").reset().toString()); - ConsoleUtils.info("all tests passed"); + // test if ipc is accessible + ConsoleUtils.infoNOLF("testing ipc connection..."); + final IPCClient client = new IPCClient(); + client.send(new IPCMessage(IPCMessageCode.TEST)); + client.close(); + ConsoleUtils.print(Ansi.ansi().fg(Color.GREEN).a("OK").reset().toString()); + + // test if elasticsearch is accessible + ConsoleUtils.infoNOLF("testing elasticsearch connection..."); + final TransportClient esclient = ESClient.getClient(config); + if (esclient.connectedNodes().isEmpty()) + throw new NoNodeAvailableException("no elasticsearch nodes available"); + ConsoleUtils.print(Ansi.ansi().fg(Color.GREEN).a("OK").reset().toString()); + + // test if spotlight is accessible + if (config.isSpotlightEnabled()) { + ConsoleUtils.infoNOLF("testing spotlight connection..."); + final URL url = new URL(config.getSpotlightUrl() + "/rest/application.wadl"); + final HttpURLConnection huc = (HttpURLConnection) url.openConnection(); + huc.setRequestMethod("HEAD"); + if (huc.getResponseCode() != 200) + throw new Exception("spotlight server not available"); + ConsoleUtils.print(Ansi.ansi().fg(Color.GREEN).a("OK").reset().toString()); + } + + ConsoleUtils.info("all tests passed"); + } catch (Exception e) { + ConsoleUtils.print(Ansi.ansi().fg(Color.RED).a("FAILED").reset().toString()); + throw e; + } } } diff --git a/vipra-cmd/src/main/resources/config.json b/vipra-cmd/src/main/resources/config.json index ba2f39ecd81d944babd2e72b54baa7d30f11ab65..0bf0320a68e42aecc4b004db2c56e55f1dbe217f 100644 --- a/vipra-cmd/src/main/resources/config.json +++ b/vipra-cmd/src/main/resources/config.json @@ -5,8 +5,10 @@ "databaseName": "test", "elasticSearchHost": "127.0.0.1", "elasticSearchPort": 9300, + "ipcHost": "127.0.0.1", + "ipcPort": 6789, "spotlightUrl": "", - "dtmPath": "", + "dtmPath": "/opt/vipra/dtm_release/dtm/main", "modelConfigTemplate": { "name": "", "kTopics": 20, diff --git a/vipra-ui/app/js/app.js b/vipra-ui/app/js/app.js index a5374727954992cdf9090a1efd66fcda9b35917a..25a3d9b9a405691cf9e825e3018dc7f5d347a343 100644 --- a/vipra-ui/app/js/app.js +++ b/vipra-ui/app/js/app.js @@ -2,7 +2,7 @@ * Vipra Application * Main application file ******************************************************************************/ -/* globals angular, $ */ +/* globals angular, $, Vipra */ (function() { "use strict"; @@ -11,6 +11,7 @@ 'ngResource', 'ngSanitize', 'ngAnimate', + 'ngWebSocket', 'ui.router', 'cfp.hotkeys', 'nya.bootstrap.select', @@ -200,7 +201,7 @@ } ]); - app.run(['$rootScope', '$state', function($rootScope, $state) { + app.run(['$rootScope', '$state', '$websocket', function($rootScope, $state, $websocket) { $rootScope.loading = {}; @@ -223,6 +224,12 @@ $rootScope.alerts = []; }); + var socket = $websocket(Vipra.config.websocketUrl); + + socket.onMessage(function(message) { + console.log(message.data); + }); + }]); $(document).on('change', '.btn-file :file', function() { diff --git a/vipra-ui/app/js/config.js b/vipra-ui/app/js/config.js index 397d96104139282185428e5b6d7e7bbb26025955..6a10054bf69fd58cbcb0b0a6eb2d8df80251ab43 100644 --- a/vipra-ui/app/js/config.js +++ b/vipra-ui/app/js/config.js @@ -19,7 +19,12 @@ * ^^^^^ * this is the restUrl */ - restUrl: '/rest' + restUrl: '/rest', + + /* + * Point this URL to the backend websocket. The default is /ws. + */ + websocketUrl: '/ws' }; })(); \ No newline at end of file diff --git a/vipra-ui/app/less/app.less b/vipra-ui/app/less/app.less index c846d7cb5197b870ea0dd9a54202f0b4c103f25c..4534a0062003ba89e6c407f7b4be94ae7092c26f 100644 --- a/vipra-ui/app/less/app.less +++ b/vipra-ui/app/less/app.less @@ -14,6 +14,14 @@ body { padding-bottom: 20px; } +html, body { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; +} + +svg { + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif !important; +} + .info, .pointer, input[type=checkbox], @@ -235,6 +243,12 @@ a:hover { display: inline-block; width: 100%; vertical-align: middle; + position: relative; + + .badge { + position: absolute; + right: 0; + } } .colorbox { @@ -713,8 +727,11 @@ entity-menu { .index { .navbar-default { - border-color: transparent; + border: 0; background: rgba(255,255,255,0.6); + .navbar-nav>li>a { + color: #555; + } } } diff --git a/vipra-ui/bower.json b/vipra-ui/bower.json index 160ceb62dc785c0b0244357cfcb83f66e1e9c294..1d60c9d9fd99051f4f9439f28f6a4c7508a8d2c0 100644 --- a/vipra-ui/bower.json +++ b/vipra-ui/bower.json @@ -22,6 +22,8 @@ "angular": "^1.x", "angular-resource": "^1.x", "angular-sanitize": "^1.x", + "angular-animate": "^1.x", + "angular-websocket": "^1.x", "angular-ui-router": "^0.x", "highcharts": "^4.x", "vis": "^4.x", @@ -32,7 +34,6 @@ "randomcolor": "randomColor#^0.x", "bootbox.js": "bootbox#^4.x", "angular-hotkeys": "chieffancypants/angular-hotkeys#^1.x", - "eonasdan-bootstrap-datetimepicker": "^4.17.37", - "angular-animate": "^1.5.5" + "eonasdan-bootstrap-datetimepicker": "^4.x" } } diff --git a/vipra-ui/build.sh b/vipra-ui/build.sh index ee2f1c881fd2a425cb23141b67e71594b77bcc08..511106b8b0612914b99f1327d6c685dd4aadad3e 100755 --- a/vipra-ui/build.sh +++ b/vipra-ui/build.sh @@ -5,5 +5,6 @@ rm -rf public npm install bower install gulp build +gulp compress exit 0 diff --git a/vipra-ui/gulpfile.js b/vipra-ui/gulpfile.js index fb129804a544517dfc9e7eca0156ac7e21e9761b..6d8a564aa7e222ec94e1718b01b9f25e7b76123a 100644 --- a/vipra-ui/gulpfile.js +++ b/vipra-ui/gulpfile.js @@ -1,6 +1,7 @@ /* jshint ignore: start */ var gulp = require('gulp'), + gzip = require('gulp-gzip'), less = require('gulp-less'), concat = require('gulp-concat'), uglify = require('gulp-uglify'), @@ -16,6 +17,7 @@ var assets = { 'bower_components/angular-resource/angular-resource.min.js', 'bower_components/angular-sanitize/angular-sanitize.min.js', 'bower_components/angular-animate/angular-animate.min.js', + 'bower_components/angular-websocket/angular-websocket.min.js', 'bower_components/angular-hotkeys/build/hotkeys.min.js', 'bower_components/angular-ui-router/release/angular-ui-router.min.js', 'bower_components/bootstrap/dist/js/bootstrap.min.js', @@ -44,6 +46,13 @@ var assets = { img: [] }; +var gzip_options = { + threshold: 1400, + gzipOptions: { + level: 6 + } +}; + gulp.task('less', function() { gulp.src('app/less/**/*.less') .pipe(concat('app.css')) @@ -65,8 +74,10 @@ gulp.task('js-rel', function() { gulp.src(['app/js/**/*.js', '!app/js/config.js']) .pipe(concat('app.js')) .pipe(ngannotate()) + .pipe(uglify()) .pipe(gulp.dest('public/js')); gulp.src('app/js/config.js') + .pipe(uglify()) .pipe(gulp.dest('public/js')); }); @@ -108,7 +119,42 @@ gulp.task('assets', function() { .pipe(gulp.dest('public/img')); }); -gulp.task('build', ['less', 'js-rel', 'html', 'img', 'public', 'assets']); +gulp.task('assets-rel', function() { + gulp.src(assets.js) + .pipe(concat('vendor.js')) + .pipe(uglify()) + .pipe(gulp.dest('public/js')); + gulp.src(assets.css) + .pipe(cleancss()) + .pipe(concat('vendor.css')) + .pipe(gulp.dest('public/css')); + gulp.src(assets.fonts) + .pipe(gulp.dest('public/fonts')); + gulp.src(assets.img) + .pipe(gulp.dest('public/img')); +}); + +gulp.task('compress', function() { + gulp.src('public/css/**/*') + .pipe(gzip(gzip_options)) + .pipe(gulp.dest('public/css')); + gulp.src('public/fonts/**/*') + .pipe(gzip(gzip_options)) + .pipe(gulp.dest('public/fonts')); + gulp.src('public/html/**/*') + .pipe(gzip(gzip_options)) + .pipe(gulp.dest('public/html')); + gulp.src('public/js/**/*') + .pipe(gzip(gzip_options)) + .pipe(gulp.dest('public/js')); + gulp.src('public/*') + .pipe(gzip(gzip_options)) + .pipe(gulp.dest('public')); +}); + +gulp.task('build-dev', ['less', 'js', 'html', 'img', 'public', 'assets']); + +gulp.task('build', ['less', 'js-rel', 'html', 'img', 'public', 'assets-rel']); gulp.task('watch', function() { gulp.watch('app/less/**/*.less', ['less']); diff --git a/vipra-ui/package.json b/vipra-ui/package.json index 87e1b48fb71a60a14f22100337443935cee55579..6a28e95a2321e383701656553b6cbd9dd633794f 100644 --- a/vipra-ui/package.json +++ b/vipra-ui/package.json @@ -11,6 +11,7 @@ "gulp-clean-css": "^2.0.3", "gulp-concat": "^2.6.0", "gulp-cssnano": "^2.1.0", + "gulp-gzip": "^1.2.0", "gulp-include": "^2.1.0", "gulp-less": "^3.0.5", "gulp-ng-annotate": "^2.0.0", diff --git a/vipra-util/src/main/java/de/vipra/util/Config.java b/vipra-util/src/main/java/de/vipra/util/Config.java index 391410401838bbb89e7eb949d3e576edd91e1da5..55fec90e8ae55c106a1c47135f74398797d36cb7 100644 --- a/vipra-util/src/main/java/de/vipra/util/Config.java +++ b/vipra-util/src/main/java/de/vipra/util/Config.java @@ -42,6 +42,8 @@ public class Config { private String databaseName = Constants.DATABASE_NAME; private String elasticSearchHost = Constants.ES_HOST; private int elasticSearchPort = Constants.ES_PORT; + private String ipcHost = Constants.IPC_HOST; + private int ipcPort = Constants.IPC_PORT; private TopicModelConfig modelConfigTemplate = new TopicModelConfig(); private String spotlightUrl; private String dtmPath; @@ -89,6 +91,26 @@ public class Config { this.elasticSearchPort = elasticSearchPort; } + public String getIpcHost() { + return ipcHost; + } + + public void setIpcHost(final String ipcHost) { + this.ipcHost = ipcHost; + } + + public int getIpcPort() { + return ipcPort; + } + + public void setIpcPort(final int ipcPort) { + this.ipcPort = ipcPort; + } + + public boolean isSpotlightEnabled() { + return spotlightUrl != null && !spotlightUrl.isEmpty(); + } + public String getSpotlightUrl() { return spotlightUrl; } @@ -212,6 +234,10 @@ public class Config { } public static Config getConfig() throws ConfigException { + return getConfig(false); + } + + public static Config getConfig(boolean skipModels) throws ConfigException { if (instance == null) { try { InputStream in = null; @@ -255,12 +281,14 @@ public class Config { throw new ConfigException("could not read configuration"); // read topic model configs - final MongoService<TopicModelFull, String> dbTopicModels = MongoService.getDatabaseService(instance, TopicModelFull.class); - final List<TopicModelFull> topicModels = dbTopicModels.getAll("_all"); - final Map<String, TopicModelConfig> topicModelConfigs = new HashMap<>(topicModels.size()); - for (final TopicModelFull topicModel : topicModels) - topicModelConfigs.put(topicModel.getId(), topicModel.getModelConfig()); - instance.setTopicModelConfigs(topicModelConfigs); + if (!skipModels) { + final MongoService<TopicModelFull, String> dbTopicModels = MongoService.getDatabaseService(instance, TopicModelFull.class); + final List<TopicModelFull> topicModels = dbTopicModels.getAll("_all"); + final Map<String, TopicModelConfig> topicModelConfigs = new HashMap<>(topicModels.size()); + for (final TopicModelFull topicModel : topicModels) + topicModelConfigs.put(topicModel.getId(), topicModel.getModelConfig()); + instance.setTopicModelConfigs(topicModelConfigs); + } } catch (final IOException e) { throw new ConfigException(e); } diff --git a/vipra-util/src/main/java/de/vipra/util/ConsoleUtils.java b/vipra-util/src/main/java/de/vipra/util/ConsoleUtils.java index 395375440c6202abedfcc0f7d82ccfd7c03a384f..c751672eb648876368351be553c9586b722c349f 100644 --- a/vipra-util/src/main/java/de/vipra/util/ConsoleUtils.java +++ b/vipra-util/src/main/java/de/vipra/util/ConsoleUtils.java @@ -93,6 +93,14 @@ public class ConsoleUtils { return error(t.getMessage()); } + public static int print(final String msg) { + return print(System.out, true, msg); + } + + public static int printNOLF(final String msg) { + return print(System.out, false, msg); + } + public static double readDouble(String message, final Double def, final Double min, final Double max, final boolean showBounds) { final BufferedReader in = new BufferedReader(new InputStreamReader(System.in)); if (showBounds) diff --git a/vipra-util/src/main/java/de/vipra/util/Constants.java b/vipra-util/src/main/java/de/vipra/util/Constants.java index 936f6b4e432ed6977afc9e5f2a979215d59f2ddb..edc7792a412a6f7679412e04ce9e3919b6bc78bf 100644 --- a/vipra-util/src/main/java/de/vipra/util/Constants.java +++ b/vipra-util/src/main/java/de/vipra/util/Constants.java @@ -45,6 +45,12 @@ public class Constants { public static final String ES_HOST = "127.0.0.1"; public static final int ES_PORT = 9300; + /* + * IPC + */ + public static final String IPC_HOST = "127.0.0.1"; + public static final int IPC_PORT = 6789; + /** * Topic boost parameter. Boosts topic importance in queries. Default 4. */ diff --git a/vipra-util/src/main/java/de/vipra/util/CountMatrix.java b/vipra-util/src/main/java/de/vipra/util/CountMatrix.java index 7177ddc24eb8d51b497054ba22ffaf91e55cecae..feac46bf448144a649be801818174e6b5f213384 100644 --- a/vipra-util/src/main/java/de/vipra/util/CountMatrix.java +++ b/vipra-util/src/main/java/de/vipra/util/CountMatrix.java @@ -2,7 +2,7 @@ package de.vipra.util; public class CountMatrix<T, U> extends Matrix<T, U, Integer> { - public void count(T t, U u) { + public void count(final T t, final U u) { Integer i = get(t, u); if (i == null) i = 1; diff --git a/vipra-util/src/main/java/de/vipra/util/IPCChain.java b/vipra-util/src/main/java/de/vipra/util/IPCChain.java new file mode 100644 index 0000000000000000000000000000000000000000..825e3f88f38b6e1f33b9261883bb77f544404764 --- /dev/null +++ b/vipra-util/src/main/java/de/vipra/util/IPCChain.java @@ -0,0 +1,7 @@ +package de.vipra.util; + +public interface IPCChain { + + void call(IPCMessage message); + +} diff --git a/vipra-util/src/main/java/de/vipra/util/IPCClient.java b/vipra-util/src/main/java/de/vipra/util/IPCClient.java new file mode 100644 index 0000000000000000000000000000000000000000..46fd449dca538fd1cc81a9b91e8eef3a08654581 --- /dev/null +++ b/vipra-util/src/main/java/de/vipra/util/IPCClient.java @@ -0,0 +1,36 @@ +package de.vipra.util; + +import java.io.Closeable; +import java.io.DataOutputStream; +import java.io.IOException; +import java.net.Socket; +import java.net.UnknownHostException; + +import de.vipra.util.ex.ConfigException; + +public class IPCClient implements Closeable { + + private final Socket socket; + private final DataOutputStream out; + + public IPCClient() throws ConfigException, UnknownHostException, IOException { + final Config config = Config.getConfig(); + socket = new Socket(config.getIpcHost(), config.getIpcPort()); + out = new DataOutputStream(socket.getOutputStream()); + } + + public IPCClient send(final IPCMessage message) throws IOException { + if (!socket.isClosed()) { + final String messageStr = Config.mapper.writeValueAsString(message); + out.writeUTF(messageStr); + out.flush(); + } + return this; + } + + @Override + public void close() throws IOException { + socket.close(); + } + +} diff --git a/vipra-util/src/main/java/de/vipra/util/IPCMessage.java b/vipra-util/src/main/java/de/vipra/util/IPCMessage.java new file mode 100644 index 0000000000000000000000000000000000000000..f26bf871484b3abb0b8cbad7ce2ec0ef426d4c6f --- /dev/null +++ b/vipra-util/src/main/java/de/vipra/util/IPCMessage.java @@ -0,0 +1,36 @@ +package de.vipra.util; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class IPCMessage { + + private IPCMessageCode code; + + private String message; + + public IPCMessage() {} + + public IPCMessage(final IPCMessageCode code) { + this.code = code; + } + + public IPCMessageCode getCode() { + return code; + } + + public IPCMessage code(final IPCMessageCode code) { + this.code = code; + return this; + } + + public String getMessage() { + return message; + } + + public IPCMessage message(final String message) { + this.message = message; + return this; + } + +} diff --git a/vipra-util/src/main/java/de/vipra/util/IPCMessageCode.java b/vipra-util/src/main/java/de/vipra/util/IPCMessageCode.java new file mode 100644 index 0000000000000000000000000000000000000000..59fb104e6de77561ba5839bc6265a3cdddae2bc0 --- /dev/null +++ b/vipra-util/src/main/java/de/vipra/util/IPCMessageCode.java @@ -0,0 +1,12 @@ +package de.vipra.util; + +public enum IPCMessageCode { + TEST, + MESSAGE, + START_MODELING, + STOP_MODELING, + START_INDEXING, + STOP_INDEXING, + START_IMPORTING, + STOP_IMPORTING +} \ No newline at end of file diff --git a/vipra-util/src/main/java/de/vipra/util/IPCServer.java b/vipra-util/src/main/java/de/vipra/util/IPCServer.java new file mode 100644 index 0000000000000000000000000000000000000000..ba440f5dc163b04a5fb164c6e13e872929824386 --- /dev/null +++ b/vipra-util/src/main/java/de/vipra/util/IPCServer.java @@ -0,0 +1,77 @@ +package de.vipra.util; + +import java.io.DataInputStream; +import java.io.IOException; +import java.net.ServerSocket; +import java.net.Socket; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Map.Entry; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import de.vipra.util.ex.ConfigException; + +public class IPCServer extends Thread { + + public static final Logger log = LoggerFactory.getLogger(IPCServer.class); + private static IPCServer instance; + + private final Map<String, IPCChain> chains = new LinkedHashMap<>(); + + @SuppressWarnings("resource") + @Override + public void run() { + Config config = null; + ServerSocket welcomeSocket = null; + try { + config = Config.getConfig(); + welcomeSocket = new ServerSocket(config.getIpcPort()); + } catch (ConfigException | IOException e) { + log.error(e.getMessage()); + } + + while (true) { + try { + final Socket connectionSocket = welcomeSocket.accept(); + final DataInputStream in = new DataInputStream(connectionSocket.getInputStream()); + final String input = in.readUTF(); + final IPCMessage message = Config.mapper.readValue(input, IPCMessage.class); + if (message.getCode() != IPCMessageCode.TEST) + handleMessage(message); + } catch (final IOException e) { + log.error(e.getMessage()); + } + } + } + + @Override + public void start() { + if (!isAlive()) + super.start(); + } + + public void register(final String id, final IPCChain chain) { + chains.put(id, chain); + } + + private void handleMessage(final IPCMessage message) { + log.info("message received: " + message.getCode()); + for (final Entry<String, IPCChain> chain : chains.entrySet()) { + try { + chain.getValue().call(message); + } catch (final Exception e) { + log.error(e.getMessage()); + } + } + } + + public static IPCServer getInstance() { + if (instance == null) { + instance = new IPCServer(); + } + return instance; + } + +} diff --git a/vipra-util/src/main/java/de/vipra/util/LockFile.java b/vipra-util/src/main/java/de/vipra/util/LockFile.java new file mode 100644 index 0000000000000000000000000000000000000000..216989340578db7cf236ada2282da927d274efcc --- /dev/null +++ b/vipra-util/src/main/java/de/vipra/util/LockFile.java @@ -0,0 +1,34 @@ +package de.vipra.util; + +import java.io.File; +import java.io.IOException; + +import de.vipra.util.ex.LockFileException; + +public class LockFile { + + private File file = new File(PathUtils.tempDir(), "vipra.lock"); + + public void lock() throws LockFileException { + if (file.exists()) + throw new LockFileException(); + try { + file.createNewFile(); + } catch (final IOException e) { + throw new LockFileException(e); + } + } + + public void unlock() throws LockFileException { + try { + file.delete(); + } catch (final SecurityException e) { + throw new LockFileException(e); + } + } + + public String getPath() { + return file.getAbsolutePath(); + } + +} diff --git a/vipra-util/src/main/java/de/vipra/util/Matrix.java b/vipra-util/src/main/java/de/vipra/util/Matrix.java index adfb46443392fa933efa510cb39c473686701dde..3d3375149d9a22da19f9c41f783000a0c32ca74c 100644 --- a/vipra-util/src/main/java/de/vipra/util/Matrix.java +++ b/vipra-util/src/main/java/de/vipra/util/Matrix.java @@ -16,14 +16,14 @@ public class Matrix<T, U, V> { colMap = new HashMap<>(); } - public Matrix(int rowSize, int colSize) { + public Matrix(final int rowSize, final int colSize) { rowMap = new HashMap<>(rowSize); colMap = new HashMap<>(colSize); startRowSize = rowSize; startColSize = colSize; } - public V put(T t, U u, V v) { + public V put(final T t, final U u, final V v) { Map<U, V> row = rowMap.get(t); Map<T, V> col = colMap.get(u); V oldV = null; @@ -42,8 +42,8 @@ public class Matrix<T, U, V> { return oldV; } - public V get(T t, U u) { - Map<U, V> subMap = rowMap.get(t); + public V get(final T t, final U u) { + final Map<U, V> subMap = rowMap.get(t); if (subMap == null) return null; return subMap.get(u); @@ -51,16 +51,16 @@ public class Matrix<T, U, V> { public int size() { int size = 0; - for (Map<U, V> subMap : rowMap.values()) + for (final Map<U, V> subMap : rowMap.values()) size += subMap.size(); return size; } - public Map<U, V> row(T t) { + public Map<U, V> row(final T t) { return rowMap.get(t); } - public Map<T, V> col(U u) { + public Map<T, V> col(final U u) { return colMap.get(u); } diff --git a/vipra-util/src/main/java/de/vipra/util/PathUtils.java b/vipra-util/src/main/java/de/vipra/util/PathUtils.java index 4275979ab03b3c9952f77d94a8491db0e5db522c..63ade27aa543b6b786bba6e6ddff0fba8c5c3700 100644 --- a/vipra-util/src/main/java/de/vipra/util/PathUtils.java +++ b/vipra-util/src/main/java/de/vipra/util/PathUtils.java @@ -30,4 +30,8 @@ public class PathUtils { return base; } + public static File tempDir() { + return new File(System.getProperty("java.io.tmpdir")); + } + } diff --git a/vipra-util/src/main/java/de/vipra/util/ex/LockFileException.java b/vipra-util/src/main/java/de/vipra/util/ex/LockFileException.java new file mode 100644 index 0000000000000000000000000000000000000000..780d7472a3a504a6f273c5caec30734a89e93040 --- /dev/null +++ b/vipra-util/src/main/java/de/vipra/util/ex/LockFileException.java @@ -0,0 +1,16 @@ +package de.vipra.util.ex; + +@SuppressWarnings("serial") +public class LockFileException extends Exception { + + public LockFileException() {} + + public LockFileException(final String msg) { + super(msg); + } + + public LockFileException(final Throwable t) { + super(t); + } + +} diff --git a/vipra-util/src/main/java/de/vipra/util/model/ArticleFull.java b/vipra-util/src/main/java/de/vipra/util/model/ArticleFull.java index 1f905fc7d0429b817403f8887d511d9825102653..a4bf05c0ce1aa10a927616d10f2305eb03809045 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/ArticleFull.java +++ b/vipra-util/src/main/java/de/vipra/util/model/ArticleFull.java @@ -163,7 +163,7 @@ public class ArticleFull implements Model<ObjectId>, Serializable { return window; } - public void setWindow(Window window) { + public void setWindow(final Window window) { this.window = window; } @@ -210,7 +210,7 @@ public class ArticleFull implements Model<ObjectId>, Serializable { final List<String> topics = new ArrayList<>(refs.size()); for (final TopicShare ref : refs) { final Topic topic = ref.getTopic(); - if(topic != null) + if (topic != null) topics.add(topic.getName()); } return topics.toArray(new String[topics.size()]); diff --git a/vipra-util/src/main/java/de/vipra/util/model/ArticleStats.java b/vipra-util/src/main/java/de/vipra/util/model/ArticleStats.java index c8d25ee66bf0a85c78941779917aee8068219501..9044fb551c0aa9f703230b9a2dcdc8e688d8ff7b 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/ArticleStats.java +++ b/vipra-util/src/main/java/de/vipra/util/model/ArticleStats.java @@ -13,11 +13,11 @@ public class ArticleStats implements Serializable { private static final long serialVersionUID = -4712841724990200627L; private Long wordCount; - + private Long uniqueWordCount; - + private Long processedWordCount; - + private Double reductionRatio; public Long getWordCount() { diff --git a/vipra-util/src/main/java/de/vipra/util/model/TopicFull.java b/vipra-util/src/main/java/de/vipra/util/model/TopicFull.java index 6424111e156e32ed7a701fab8a4af7da0f856ec7..5947d68087714e087ccc46dca28fc46927103f1c 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/TopicFull.java +++ b/vipra-util/src/main/java/de/vipra/util/model/TopicFull.java @@ -118,7 +118,7 @@ public class TopicFull implements Model<ObjectId>, Serializable { return similarTopics; } - public void setSimilarTopics(List<TopicShare> similarTopics) { + public void setSimilarTopics(final List<TopicShare> similarTopics) { this.similarTopics = similarTopics; } diff --git a/vipra-util/src/main/java/de/vipra/util/model/WindowFull.java b/vipra-util/src/main/java/de/vipra/util/model/WindowFull.java index 738b75171d45b6fb7cfed26699e833815f962ed2..be133bdcf06b715aaf23a06e12eabf0aac2e6d5b 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/WindowFull.java +++ b/vipra-util/src/main/java/de/vipra/util/model/WindowFull.java @@ -29,11 +29,11 @@ public class WindowFull implements Model<String>, Serializable, Comparable<Windo public WindowFull() {} - public WindowFull(Window window) { - this.id = Long.toString(window.getStartDate().getTime()); - this.startDate = window.getStartDate(); - this.endDate = window.getEndDate(); - this.windowResolution = window.getWindowResolution(); + public WindowFull(final Window window) { + id = Long.toString(window.getStartDate().getTime()); + startDate = window.getStartDate(); + endDate = window.getEndDate(); + windowResolution = window.getWindowResolution(); } @Override @@ -42,7 +42,7 @@ public class WindowFull implements Model<String>, Serializable, Comparable<Windo } @Override - public void setId(String id) { + public void setId(final String id) { this.id = id; } @@ -50,7 +50,7 @@ public class WindowFull implements Model<String>, Serializable, Comparable<Windo return startDate; } - public void setStartDate(Date startDate) { + public void setStartDate(final Date startDate) { this.startDate = startDate; } @@ -58,7 +58,7 @@ public class WindowFull implements Model<String>, Serializable, Comparable<Windo return endDate; } - public void setEndDate(Date endDate) { + public void setEndDate(final Date endDate) { this.endDate = endDate; } @@ -66,7 +66,7 @@ public class WindowFull implements Model<String>, Serializable, Comparable<Windo return windowResolution; } - public void setWindowResolution(WindowResolution windowResolution) { + public void setWindowResolution(final WindowResolution windowResolution) { this.windowResolution = windowResolution; } @@ -74,12 +74,12 @@ public class WindowFull implements Model<String>, Serializable, Comparable<Windo return topicModel; } - public void setTopicModel(TopicModel topicModel) { + public void setTopicModel(final TopicModel topicModel) { this.topicModel = topicModel; } @Override - public int compareTo(WindowFull o) { + public int compareTo(final WindowFull o) { return startDate.compareTo(o.getStartDate()); } } diff --git a/vipra-util/src/main/java/de/vipra/util/model/WordFull.java b/vipra-util/src/main/java/de/vipra/util/model/WordFull.java index 071156f080592f1cd979b5988bd66df22c9a4611..4f58b20f50cd143d21d9b37653b54798eed7efd4 100644 --- a/vipra-util/src/main/java/de/vipra/util/model/WordFull.java +++ b/vipra-util/src/main/java/de/vipra/util/model/WordFull.java @@ -53,7 +53,7 @@ public class WordFull implements Model<String>, Comparable<WordFull>, Serializab return created; } - public void setCreated(Date created) { + public void setCreated(final Date created) { this.created = created; } @@ -61,7 +61,7 @@ public class WordFull implements Model<String>, Comparable<WordFull>, Serializab return modified; } - public void setModified(Date modified) { + public void setModified(final Date modified) { this.modified = modified; }