Skip to content
Snippets Groups Projects
Commit e4ecaceb authored by Eike Cochu's avatar Eike Cochu
Browse files

generalized util services

fixed import option exception structure
parent 87c90698
Branches
No related tags found
No related merge requests found
Showing
with 204 additions and 95 deletions
...@@ -2,7 +2,6 @@ package de.vipra.cmd; ...@@ -2,7 +2,6 @@ package de.vipra.cmd;
import org.apache.commons.cli.HelpFormatter; import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option; import org.apache.commons.cli.Option;
import org.apache.commons.cli.OptionGroup;
import org.apache.commons.cli.Options; import org.apache.commons.cli.Options;
public class CmdOptions extends Options { public class CmdOptions extends Options {
...@@ -10,6 +9,7 @@ public class CmdOptions extends Options { ...@@ -10,6 +9,7 @@ public class CmdOptions extends Options {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
public static final String OPT_HELP = "h"; public static final String OPT_HELP = "h";
public static final String OPT_HELP_LONG = "help";
public static final String OPT_IMPORT = "i"; public static final String OPT_IMPORT = "i";
public static final String OPT_SHELL = "x"; public static final String OPT_SHELL = "x";
...@@ -17,14 +17,9 @@ public class CmdOptions extends Options { ...@@ -17,14 +17,9 @@ public class CmdOptions extends Options {
addOption(Option.builder(OPT_HELP).longOpt("help").desc("print this message").build()); addOption(Option.builder(OPT_HELP).longOpt("help").desc("print this message").build());
addOption(Option.builder(OPT_SHELL).longOpt("shell").hasArg(true).argName("name") addOption(Option.builder(OPT_SHELL).longOpt("shell").hasArg(true).argName("name")
.desc("run from a shell script").build()); .desc("run from a shell script").build());
addOption(Option.builder(OPT_IMPORT).longOpt("import").hasArgs().argName("files/dirs...")
OptionGroup opts = new OptionGroup();
opts.setRequired(true);
opts.addOption(Option.builder(OPT_IMPORT).longOpt("import").hasArgs().argName("files/dirs...")
.desc("import articles into the database").build()); .desc("import articles into the database").build());
addOptionGroup(opts);
} }
public void printHelp(String cmd) { public void printHelp(String cmd) {
......
...@@ -4,8 +4,6 @@ import static de.vipra.cmd.CmdOptions.OPT_HELP; ...@@ -4,8 +4,6 @@ import static de.vipra.cmd.CmdOptions.OPT_HELP;
import static de.vipra.cmd.CmdOptions.OPT_IMPORT; import static de.vipra.cmd.CmdOptions.OPT_IMPORT;
import static de.vipra.cmd.CmdOptions.OPT_SHELL; import static de.vipra.cmd.CmdOptions.OPT_SHELL;
import java.io.IOException;
import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser; import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser; import org.apache.commons.cli.DefaultParser;
...@@ -13,19 +11,27 @@ import org.apache.commons.cli.ParseException; ...@@ -13,19 +11,27 @@ import org.apache.commons.cli.ParseException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import de.vipra.cmd.option.ImportOption; import de.vipra.cmd.option.Command;
import de.vipra.util.ConfigException; import de.vipra.cmd.option.ImportCommand;
public class Main { public class Main {
public static final Logger log = LoggerFactory.getLogger(Main.class); public static final Logger log = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) throws IOException, ConfigException { public static void main(String[] args) {
CommandLineParser parser = new DefaultParser(); CommandLineParser parser = new DefaultParser();
CmdOptions options = new CmdOptions(); CmdOptions options = new CmdOptions();
String cmd = "vipra-cmd.jar"; String cmd = "vipra-cmd.jar";
CommandLine cline;
try {
cline = parser.parse(options, args);
} catch (ParseException e) {
log.error(e.getMessage());
options.printHelp(cmd);
return;
}
try { try {
CommandLine cline = parser.parse(options, args);
if (cline.hasOption(OPT_SHELL)) { if (cline.hasOption(OPT_SHELL)) {
cmd = cline.getOptionValue(OPT_SHELL); cmd = cline.getOptionValue(OPT_SHELL);
if (cmd == null) { if (cmd == null) {
...@@ -33,18 +39,20 @@ public class Main { ...@@ -33,18 +39,20 @@ public class Main {
} }
} }
Command c = null;
if (cline.hasOption(OPT_HELP)) { if (cline.hasOption(OPT_HELP)) {
options.printHelp(cmd); options.printHelp(cmd);
} else if (cline.hasOption(OPT_IMPORT)) { } else if (cline.hasOption(OPT_IMPORT)) {
String[] paths = cline.getOptionValues(OPT_IMPORT); String[] paths = cline.getOptionValues(OPT_IMPORT);
ImportOption opt = new ImportOption(paths); c = new ImportCommand(paths);
opt.doImport(); }
if (c != null) {
c.run();
} else { } else {
options.printHelp(cmd); options.printHelp(cmd);
} }
} catch (ParseException e) {
log.error(e.getMessage());
options.printHelp(cmd);
} catch (ExecutionException e) { } catch (ExecutionException e) {
log.error(e.getMessage()); log.error(e.getMessage());
} }
......
package de.vipra.cmd.option;
import de.vipra.cmd.ExecutionException;
public interface Command {
public void run() throws ExecutionException;
}
...@@ -7,17 +7,12 @@ import java.io.IOException; ...@@ -7,17 +7,12 @@ import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.bson.Document;
import org.json.simple.JSONArray; import org.json.simple.JSONArray;
import org.json.simple.JSONObject; import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser; import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import de.vipra.cmd.ExecutionException; import de.vipra.cmd.ExecutionException;
import de.vipra.cmd.model.Article; import de.vipra.cmd.model.Article;
import de.vipra.util.Config; import de.vipra.util.Config;
...@@ -25,18 +20,23 @@ import de.vipra.util.ConfigException; ...@@ -25,18 +20,23 @@ import de.vipra.util.ConfigException;
import de.vipra.util.Constants; import de.vipra.util.Constants;
import de.vipra.util.Mongo; import de.vipra.util.Mongo;
import de.vipra.util.StringUtils; import de.vipra.util.StringUtils;
import de.vipra.util.ex.DatabaseException;
import de.vipra.util.ex.FilebaseException;
import de.vipra.util.service.DatabaseService;
import de.vipra.util.service.FilebaseService;
public class ImportOption { public class ImportCommand implements Command {
public static final Logger log = LoggerFactory.getLogger(ImportOption.class); public static final Logger log = LoggerFactory.getLogger(ImportCommand.class);
public static final Logger out = LoggerFactory.getLogger("shellout"); public static final Logger out = LoggerFactory.getLogger("shellout");
private ArrayList<File> files = new ArrayList<>(); private ArrayList<File> files = new ArrayList<>();
private JSONParser parser = new JSONParser(); private JSONParser parser = new JSONParser();
private Config config; private Config config;
private MongoCollection<Document> collection; private DatabaseService<Article> dbArticles;
private FilebaseService<Article> fbArticles;
public ImportOption(String[] paths) throws ExecutionException { public ImportCommand(String[] paths) throws ExecutionException {
addPaths(paths); addPaths(paths);
} }
...@@ -61,42 +61,21 @@ public class ImportOption { ...@@ -61,42 +61,21 @@ public class ImportOption {
files.add(file); files.add(file);
} else if (file.isDirectory()) { } else if (file.isDirectory()) {
File[] files = file.listFiles(new FilenameFilter() { File[] files = file.listFiles(new FilenameFilter() {
@Override @Override
public boolean accept(File dir, String name) { public boolean accept(File dir, String name) {
return dir.isFile(); return dir.isFile();
} }
}); });
addPaths(files); addPaths(files);
} }
} }
private void importFile(File file) throws ExecutionException { private void importFile(File file) throws Exception {
Object data; Object data = parser.parse(new FileReader(file));
try {
data = parser.parse(new FileReader(file));
} catch (IOException e) {
throw new ExecutionException("file not found: " + file.getAbsolutePath());
} catch (ParseException e) {
throw new ExecutionException("could not parse json in file: " + file.getAbsolutePath());
}
try { try {
JSONArray array = (JSONArray) data; importArticles((JSONArray) data);
for (Object object : array) {
List<Exception> errors = new ArrayList<>();
try {
importArticle((JSONObject) object);
} catch (ExecutionException e) {
errors.add(e);
}
if (errors.size() > 0) {
throw new ExecutionException(errors);
}
}
return;
} catch (ClassCastException e) { } catch (ClassCastException e) {
try { try {
importArticle((JSONObject) data); importArticle((JSONObject) data);
...@@ -106,8 +85,21 @@ public class ImportOption { ...@@ -106,8 +85,21 @@ public class ImportOption {
} }
} }
private void importArticle(JSONObject obj) throws ExecutionException { private void importArticles(JSONArray array) throws ExecutionException {
// 2. add article to file database List<Exception> errors = new ArrayList<>();
for (Object object : array) {
try {
importArticle((JSONObject) object);
} catch (Exception e) {
errors.add(e);
}
}
if (errors.size() > 0) {
throw new ExecutionException(errors);
}
}
private void importArticle(JSONObject obj) throws FilebaseException, DatabaseException {
// 4. topic modeling // 4. topic modeling
// 3. index article via elasticsearch, include topics // 3. index article via elasticsearch, include topics
out.info("importing \"" + StringUtils.ellipsize(obj.get("title").toString(), 80) + "\""); out.info("importing \"" + StringUtils.ellipsize(obj.get("title").toString(), 80) + "\"");
...@@ -115,21 +107,20 @@ public class ImportOption { ...@@ -115,21 +107,20 @@ public class ImportOption {
article.fromJSON(obj); article.fromJSON(obj);
// add article to mongodb // add article to mongodb
Document document = article.toDocument(); article = dbArticles.createSingle(article);
try {
collection.insertOne(document);
} catch (Exception e) {
throw new ExecutionException("could not create database entry: " + e.getMessage());
}
// add article to filebase
article = fbArticles.createSingle(article);
} }
public void doImport() throws ExecutionException { @Override
public void run() throws ExecutionException {
try { try {
config = new Config(); config = new Config();
File dataDir = null;
Mongo mongo = Mongo.getInstance(config); Mongo mongo = Mongo.getInstance(config);
MongoDatabase db = mongo.getDatabase(); dbArticles = new DatabaseService<Article>(mongo, Constants.Collection.ARTICLES, Article.class);
collection = db.getCollection(Constants.Collection.ARTICLES.name); fbArticles = new FilebaseService<Article>(dataDir, Article.class);
} catch (IOException | ConfigException e) { } catch (IOException | ConfigException e) {
throw new ExecutionException(e); throw new ExecutionException(e);
} }
......
...@@ -27,6 +27,7 @@ import de.vipra.rest.service.ArticleService; ...@@ -27,6 +27,7 @@ import de.vipra.rest.service.ArticleService;
import de.vipra.util.Config; import de.vipra.util.Config;
import de.vipra.util.ConfigException; import de.vipra.util.ConfigException;
import de.vipra.util.Mongo; import de.vipra.util.Mongo;
import de.vipra.util.ex.DatabaseException;
@Path("articles") @Path("articles")
public class ArticleResource { public class ArticleResource {
...@@ -79,9 +80,16 @@ public class ArticleResource { ...@@ -79,9 +80,16 @@ public class ArticleResource {
@Consumes(APIMediaType.APPLICATION_JSONAPI) @Consumes(APIMediaType.APPLICATION_JSONAPI)
@Produces(APIMediaType.APPLICATION_JSONAPI) @Produces(APIMediaType.APPLICATION_JSONAPI)
public Response createArticle(Article article) { public Response createArticle(Article article) {
article = service.createArticle(uri.getAbsolutePath(), article); ResponseWrapper<Article> res;
ResponseWrapper<Article> res = new ResponseWrapper<>(article); try {
return Response.created(article.uri(uri.getAbsolutePath())).entity(res).build(); article = service.createArticle(uri.getAbsolutePath(), article);
res = new ResponseWrapper<>(article);
return Response.created(article.uri(uri.getAbsolutePath())).entity(res).build();
} catch (DatabaseException e) {
res = new ResponseWrapper<>(new APIError(Response.Status.INTERNAL_SERVER_ERROR, "item could not be created",
"item could not be created due to an internal server error"));
return Response.serverError().entity(res).build();
}
} }
@DELETE @DELETE
...@@ -107,20 +115,27 @@ public class ArticleResource { ...@@ -107,20 +115,27 @@ public class ArticleResource {
@Produces(APIMediaType.APPLICATION_JSONAPI) @Produces(APIMediaType.APPLICATION_JSONAPI)
@Path("{id}") @Path("{id}")
public Response updateArticle(@PathParam("id") String id, Article article) { public Response updateArticle(@PathParam("id") String id, Article article) {
long updated = service.updateArticle(uri.getAbsolutePath(), article);
int upd = updated > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) updated;
ResponseWrapper<Article> res = new ResponseWrapper<>(); ResponseWrapper<Article> res = new ResponseWrapper<>();
switch (upd) { try {
case 0: long updated = service.updateArticle(uri.getAbsolutePath(), article);
res.addError(new APIError(Response.Status.NOT_FOUND, "Article not found", int updatedInt = updated > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) updated;
String.format(Messages.NOT_FOUND, "article", id))); switch (updatedInt) {
return Response.status(Response.Status.NOT_FOUND).entity(res).build(); case 0:
case 1: res.addError(new APIError(Response.Status.NOT_FOUND, "Article not found",
res.setData(article); String.format(Messages.NOT_FOUND, "article", id)));
return Response.ok().entity(res).build(); return Response.status(Response.Status.NOT_FOUND).entity(res).build();
default: case 1:
return Response.serverError().build(); res.setData(article);
return Response.ok().entity(res).build();
default:
return Response.serverError().build();
}
} catch (DatabaseException e) {
res = new ResponseWrapper<>(new APIError(Response.Status.INTERNAL_SERVER_ERROR, "item could not be updated",
"item could not be updated due to an internal server error"));
return Response.serverError().entity(res).build();
} }
} }
} }
...@@ -6,6 +6,7 @@ import java.util.ArrayList; ...@@ -6,6 +6,7 @@ import java.util.ArrayList;
import de.vipra.rest.model.Article; import de.vipra.rest.model.Article;
import de.vipra.util.Constants; import de.vipra.util.Constants;
import de.vipra.util.Mongo; import de.vipra.util.Mongo;
import de.vipra.util.ex.DatabaseException;
import de.vipra.util.service.DatabaseService; import de.vipra.util.service.DatabaseService;
public class ArticleService extends DatabaseService<Article> { public class ArticleService extends DatabaseService<Article> {
...@@ -31,7 +32,7 @@ public class ArticleService extends DatabaseService<Article> { ...@@ -31,7 +32,7 @@ public class ArticleService extends DatabaseService<Article> {
return articles; return articles;
} }
public Article createArticle(URI base, Article article) { public Article createArticle(URI base, Article article) throws DatabaseException {
article = super.createSingle(article); article = super.createSingle(article);
if (article != null) { if (article != null) {
article.setBase(base); article.setBase(base);
...@@ -43,7 +44,7 @@ public class ArticleService extends DatabaseService<Article> { ...@@ -43,7 +44,7 @@ public class ArticleService extends DatabaseService<Article> {
return super.deleteSingle(id); return super.deleteSingle(id);
} }
public long updateArticle(URI base, Article article) { public long updateArticle(URI base, Article article) throws DatabaseException {
long updated = super.updateSingle(article); long updated = super.updateSingle(article);
article.setBase(base); article.setBase(base);
return updated; return updated;
......
package de.vipra.util.ex;
public class DatabaseException extends Exception {
private static final long serialVersionUID = 1L;
public DatabaseException(String msg) {
super(msg);
}
public DatabaseException(Exception e) {
super(e);
}
}
package de.vipra.util.ex;
public class FilebaseException extends Exception {
private static final long serialVersionUID = 1L;
public FilebaseException(String msg) {
super(msg);
}
public FilebaseException(Exception e) {
super(e);
}
}
...@@ -16,9 +16,10 @@ import com.mongodb.client.result.UpdateResult; ...@@ -16,9 +16,10 @@ import com.mongodb.client.result.UpdateResult;
import de.vipra.util.Constants; import de.vipra.util.Constants;
import de.vipra.util.Mongo; import de.vipra.util.Mongo;
import de.vipra.util.ex.DatabaseException;
import de.vipra.util.model.Model; import de.vipra.util.model.Model;
public class DatabaseService<T extends Model> { public class DatabaseService<T extends Model> implements Service<T, DatabaseException> {
private static final Logger log = LoggerFactory.getLogger(DatabaseService.class); private static final Logger log = LoggerFactory.getLogger(DatabaseService.class);
...@@ -41,7 +42,8 @@ public class DatabaseService<T extends Model> { ...@@ -41,7 +42,8 @@ public class DatabaseService<T extends Model> {
} }
} }
protected T getSingle(String id) { @Override
public T getSingle(String id) {
ArrayList<Document> result = collection.find(Filters.eq("_id", objectId(id))).into(new ArrayList<Document>()); ArrayList<Document> result = collection.find(Filters.eq("_id", objectId(id))).into(new ArrayList<Document>());
if (result.size() == 1) { if (result.size() == 1) {
return newT(result.get(0)); return newT(result.get(0));
...@@ -50,7 +52,7 @@ public class DatabaseService<T extends Model> { ...@@ -50,7 +52,7 @@ public class DatabaseService<T extends Model> {
} }
} }
protected ArrayList<T> getMultiple(int skip, int limit, String sortBy) { public ArrayList<T> getMultiple(int skip, int limit, String sortBy) {
ArrayList<Document> documents = collection.find().skip(skip).limit(limit).sort(getSorts(sortBy)) ArrayList<Document> documents = collection.find().skip(skip).limit(limit).sort(getSorts(sortBy))
.into(new ArrayList<Document>()); .into(new ArrayList<Document>());
ArrayList<T> items = new ArrayList<>(documents.size()); ArrayList<T> items = new ArrayList<>(documents.size());
...@@ -62,22 +64,34 @@ public class DatabaseService<T extends Model> { ...@@ -62,22 +64,34 @@ public class DatabaseService<T extends Model> {
return items; return items;
} }
protected T createSingle(T t) { @Override
public T createSingle(T t) throws DatabaseException {
Document document = new Document(t.toDocument()); Document document = new Document(t.toDocument());
collection.insertOne(document); try {
collection.insertOne(document);
} catch (Exception e) {
throw new DatabaseException(e);
}
t.fromDocument(document); t.fromDocument(document);
return t; return t;
} }
protected long deleteSingle(String id) { @Override
public long deleteSingle(String id) {
DeleteResult result = collection.deleteOne(Filters.eq("_id", objectId(id))); DeleteResult result = collection.deleteOne(Filters.eq("_id", objectId(id)));
return result.getDeletedCount(); return result.getDeletedCount();
} }
protected long updateSingle(T t) { @Override
public long updateSingle(T t) throws DatabaseException {
Document docOld = new Document("_id", objectId(t.getId())); Document docOld = new Document("_id", objectId(t.getId()));
Document docNew = t.toDocument(); Document docNew = t.toDocument();
UpdateResult result = collection.replaceOne(docOld, docNew); UpdateResult result;
try {
result = collection.replaceOne(docOld, docNew);
} catch (Exception e) {
throw new DatabaseException(e);
}
t.fromDocument(docNew); t.fromDocument(docNew);
return result.getModifiedCount(); return result.getModifiedCount();
} }
......
...@@ -6,9 +6,10 @@ import java.io.IOException; ...@@ -6,9 +6,10 @@ import java.io.IOException;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import de.vipra.util.ex.FilebaseException;
import de.vipra.util.model.Model; import de.vipra.util.model.Model;
public class FilebaseService<T extends Model> { public class FilebaseService<T extends Model> implements Service<T, FilebaseException> {
public static final Logger log = LoggerFactory.getLogger(FilebaseService.class); public static final Logger log = LoggerFactory.getLogger(FilebaseService.class);
...@@ -32,27 +33,57 @@ public class FilebaseService<T extends Model> { ...@@ -32,27 +33,57 @@ public class FilebaseService<T extends Model> {
} }
} }
protected File getFile(String id) { public File getFile(String id) {
return new File(directory, id); return new File(directory, id);
} }
protected T getSingle(String id) { @Override
public T getSingle(String id) {
File file = getFile(id); File file = getFile(id);
return newT(file); return newT(file);
} }
protected long deleteSingle(String id) { @Override
public T createSingle(T t) throws FilebaseException {
if (t.getId() != null) {
File file = getFile(t.getId());
if (file.exists()) {
if (!file.delete()) {
log.error("could not delete file for recreation: " + file.getAbsolutePath());
}
}
try {
t.writeToFile(file);
} catch (IOException e) {
throw new FilebaseException(e);
}
}
return t;
}
@Override
public long deleteSingle(String id) throws FilebaseException {
File file = getFile(id); File file = getFile(id);
if (file.exists() && file.delete()) { if (file.exists()) {
return 1; if (file.delete()) {
return 1;
} else {
throw new FilebaseException("could not delete file: " + file.getAbsolutePath());
}
} }
return 0; return 0;
} }
protected long updateSingle(T t) throws IOException { @Override
public long updateSingle(T t) throws FilebaseException {
File file = getFile(t.getId()); File file = getFile(t.getId());
if (file.exists()) { if (file.exists()) {
t.writeToFile(file); try {
t.writeToFile(file);
return 1;
} catch (Exception e) {
throw new FilebaseException(e);
}
} }
return 0; return 0;
} }
......
package de.vipra.util.service;
import de.vipra.util.model.Model;
public interface Service<T extends Model, E extends Exception> {
T getSingle(String id) throws E;
T createSingle(T t) throws E;
long deleteSingle(String id) throws E;
long updateSingle(T t) throws E;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment