# HG changeset patch # User Gernot Belger # Date 1594806807 -7200 # Node ID 8d11d6a17f3b4c22eceae96342f19c4c07b8800b # Parent 05caf2e731d03f82944167421a4041afe8e39c62# Parent e4dd898063a2ea4de91b5e5b1a7581af1bd1ec4d Mit 3.2.x zusammenführen diff -r e4dd898063a2 -r 8d11d6a17f3b artifact-database/pom.xml --- a/artifact-database/pom.xml Thu Jun 04 19:40:29 2020 +0200 +++ b/artifact-database/pom.xml Wed Jul 15 11:53:27 2020 +0200 @@ -91,5 +91,10 @@ jetty 6.1.26 + + org.restlet.jse + org.restlet.ext.httpclient + 2.0.7 + diff -r e4dd898063a2 -r 8d11d6a17f3b artifact-database/src/main/java/org/dive4elements/artifactdatabase/ArtifactDatabaseImpl.java --- a/artifact-database/src/main/java/org/dive4elements/artifactdatabase/ArtifactDatabaseImpl.java Thu Jun 04 19:40:29 2020 +0200 +++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/ArtifactDatabaseImpl.java Wed Jul 15 11:53:27 2020 +0200 @@ -407,6 +407,8 @@ */ protected HashMap name2service; + private Map> restServices; + /** * The factory that is used to create new artifact collections. */ @@ -464,6 +466,8 @@ protected List lifetimeListeners; + private String serverAddress; + /** * Default constructor. */ @@ -493,10 +497,13 @@ backgroundIds = new HashSet(); backgroundMsgs = new HashMap>(); + + this.serverAddress = bootstrap.getHTTPServer().getServerAddress(); setupArtifactCollectionFactory(bootstrap); setupArtifactFactories(bootstrap); setupServices(bootstrap); + setupRestServices(bootstrap); setupUserFactory(bootstrap); setupCallContextListener(bootstrap); setupHooks(bootstrap); @@ -638,6 +645,17 @@ } /** + * Used to extract the service factories from the bootstrap + * parameters, setting up the services and building the internal + * lookup tables. + * @param bootstrap The bootstrap parameters. + */ + private void setupRestServices(FactoryBootstrap bootstrap) { + + restServices = new HashMap>(bootstrap.getRestServiceNames()); + } + + /** * Wires a storage backend to this artifact database and * establishes a callback to be able to revive artifacts * via the serializers of this artifact factories. @@ -1984,5 +2002,15 @@ public String findArtifactUser(final String artifactIdentifier) { return backend.findUserName(artifactIdentifier); } + + @Override + public String getServerAddress() { + return this.serverAddress; + } + + @Override + public Map> getRestServices() { + return restServices; + } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r e4dd898063a2 -r 8d11d6a17f3b artifact-database/src/main/java/org/dive4elements/artifactdatabase/CollectionCallContext.java --- a/artifact-database/src/main/java/org/dive4elements/artifactdatabase/CollectionCallContext.java Thu Jun 04 19:40:29 2020 +0200 +++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/CollectionCallContext.java Wed Jul 15 11:53:27 2020 +0200 @@ -10,12 +10,10 @@ import java.util.LinkedList; import org.apache.log4j.Logger; - import org.dive4elements.artifacts.ArtifactCollection; import org.dive4elements.artifacts.CallMeta; import org.dive4elements.artifacts.Message; - /** * Class that implements the call context handed to ArtifactCollection specific * operations. @@ -29,51 +27,48 @@ /** * The ArtifactCollection. */ - protected ArtifactCollection collection; - + private final ArtifactCollection collection; - public CollectionCallContext( - ArtifactDatabaseImpl artifactDatabase, - int action, - CallMeta callMeta, - ArtifactCollection collection) - { + public CollectionCallContext(final ArtifactDatabaseImpl artifactDatabase, final int action, final CallMeta callMeta, final ArtifactCollection collection) { super(artifactDatabase, action, callMeta); this.collection = collection; } + public ArtifactCollection getCollection() { + return this.collection; + } - public void afterCall(int action) { + @Override + public void afterCall(final int action) { log.debug("CollectionCallContext.afterCall - NOT IMPLEMENTED"); } - - public void afterBackground(int action) { + @Override + public void afterBackground(final int action) { log.debug("CollectionCallContext.afterBackground - NOT IMPLEMENTED"); } - + @Override public boolean isInBackground() { log.debug("CollectionCallContext.isInBackground - NOT IMPLEMENTED"); return false; } - - public void addBackgroundMessage(Message msg) { + @Override + public void addBackgroundMessage(final Message msg) { log.debug("CollectionCallContext.addBackgroundMessage NOT IMPLEMENTED"); } - + @Override public LinkedList getBackgroundMessages() { log.debug("CollectionCallContext.addBackgroundMessage NOT IMPLEMENTED"); return null; } - + @Override public Long getTimeToLive() { log.debug("CollectionCallContext.getTimeToLive - NOT IMPLEMENTED"); return null; } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : +} \ No newline at end of file diff -r e4dd898063a2 -r 8d11d6a17f3b artifact-database/src/main/java/org/dive4elements/artifactdatabase/FactoryBootstrap.java --- a/artifact-database/src/main/java/org/dive4elements/artifactdatabase/FactoryBootstrap.java Thu Jun 04 19:40:29 2020 +0200 +++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/FactoryBootstrap.java Wed Jul 15 11:53:27 2020 +0200 @@ -20,11 +20,12 @@ import org.dive4elements.artifacts.UserFactory; import org.dive4elements.artifacts.common.utils.StringUtils; - import org.dive4elements.artifactdatabase.rest.HTTPServer; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.apache.log4j.Logger; @@ -70,6 +71,13 @@ "/artifact-database/factories/service-factories/service-factory"; /** + * XPath to figure out the names of the addtional restful services from + * the global configuration. + */ + public static final String RESTFUL_SERVICES = + "/artifact-database/factories/restful-services/restful-service"; + + /** * XPath to figure out the class name of the user factory from global * configuration. */ @@ -144,6 +152,8 @@ * artifact database. */ protected ArtifactFactory [] artifactFactories; + + private Map> restServices; /** * List of service factories which creates services that are @@ -361,6 +371,40 @@ new ServiceFactory[loadedFactories.size()]); } + /** + * Scans the global configuration for the configured service factories + * and sets them up. + */ + private void loadRestfulServices() { + + logger.info("loading additional restful services"); + + restServices = new HashMap>(); + + final NodeList nodes = Config.getNodeSetXPath(RESTFUL_SERVICES); + + if (nodes == null) + return; + + for (int i = 0; i < nodes.getLength(); ++i) { + + final Node node = nodes.item(i); + + final String className = Config.getStringXPath( node, "@class"); + final String path = Config.getStringXPath( node, "@path"); + + try { + final Class clazz = Class.forName(className); + restServices.put(path, clazz); + } + catch (final ClassNotFoundException cnfe) { + logger.error(cnfe.getLocalizedMessage(), cnfe); + } + catch (final ClassCastException cce) { + logger.error(cce.getLocalizedMessage(), cce); + } + } + } /** * Scans the global configuration for the configured user factory. @@ -638,6 +682,7 @@ loadCollectionFactory(); loadArtifactFactories(); loadServiceFactories(); + loadRestfulServices(); loadUserFactory(); loadCallContextListener(); loadHTTPServer(); @@ -729,5 +774,9 @@ public List getBackendListeners() { return backendListeners; } + + public Map> getRestServiceNames() { + return restServices; + } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r e4dd898063a2 -r 8d11d6a17f3b artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/HTTPServer.java --- a/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/HTTPServer.java Thu Jun 04 19:40:29 2020 +0200 +++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/HTTPServer.java Wed Jul 15 11:53:27 2020 +0200 @@ -1,13 +1,13 @@ package org.dive4elements.artifactdatabase.rest; +import org.dive4elements.artifacts.ArtifactDatabase; import org.w3c.dom.Document; -import org.dive4elements.artifacts.ArtifactDatabase; - public interface HTTPServer { void setup(Document document); void startAsServer(ArtifactDatabase database); -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : + + String getServerAddress(); +} \ No newline at end of file diff -r e4dd898063a2 -r 8d11d6a17f3b artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/RestApp.java --- a/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/RestApp.java Thu Jun 04 19:40:29 2020 +0200 +++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/RestApp.java Wed Jul 15 11:53:27 2020 +0200 @@ -8,14 +8,14 @@ package org.dive4elements.artifactdatabase.rest; -import org.dive4elements.artifacts.ArtifactDatabase; - +import java.util.Map; +import java.util.Map.Entry; import java.util.concurrent.ConcurrentMap; +import org.dive4elements.artifacts.ArtifactDatabase; import org.restlet.Application; import org.restlet.Context; import org.restlet.Restlet; - import org.restlet.routing.Router; /** @@ -25,32 +25,21 @@ * * @author Sascha L. Teichmann */ -public class RestApp -extends Application -{ +public class RestApp extends Application { + /** * The central artifact database instance to work with. */ - protected ArtifactDatabase database; - - /** - * Default constructor - */ - public RestApp() { - } - - public RestApp(Context context, ArtifactDatabase database) { - super(context); - this.database = database; - } + private final ArtifactDatabase database; /** * Constructor to create REST appliction bound to a specific * artifact database. * - * @param database The artifact database to be used. + * @param database + * The artifact database to be used. */ - public RestApp(ArtifactDatabase database) { + public RestApp(final ArtifactDatabase database) { this.database = database; } @@ -63,35 +52,35 @@ @Override public Restlet createRoot() { - Context context = getContext(); - - ConcurrentMap map = context.getAttributes(); - map.put("database", database); + final Context context = getContext(); - Router router = new Router(context); + final ConcurrentMap map = context.getAttributes(); + map.put("database", this.database); - router.attach(ServicesResource.PATH, ServicesResource.class); - router.attach(ServiceResource.PATH, ServiceResource.class); - router.attach(FactoriesResource.PATH, FactoriesResource.class); - router.attach(CreateResource.PATH, CreateResource.class); - router.attach(ArtifactResource.PATH, ArtifactResource.class); + final Router router = new Router(context); + + router.attach(ServicesResource.PATH, ServicesResource.class); + router.attach(ServiceResource.PATH, ServiceResource.class); + router.attach(FactoriesResource.PATH, FactoriesResource.class); + router.attach(CreateResource.PATH, CreateResource.class); + router.attach(ArtifactResource.PATH, ArtifactResource.class); router.attach(ArtifactOutResource.PATH, ArtifactOutResource.class); - router.attach(ExportResource.PATH, ExportResource.class); - router.attach(ImportResource.PATH, ImportResource.class); - router.attach(CreateUserResource.PATH, CreateUserResource.class); - router.attach(ListUsersResource.PATH, ListUsersResource.class); - router.attach(UserResource.PATH, UserResource.class); - router.attach(FindUserResource.PATH, FindUserResource.class); - router.attach( - CreateCollectionResource.PATH, CreateCollectionResource.class); - router.attach( - ListCollectionsResource.PATH, ListCollectionsResource.class); - router.attach( - CollectionResource.PATH, CollectionResource.class); - router.attach( - CollectionOutResource.PATH, CollectionOutResource.class); + router.attach(ExportResource.PATH, ExportResource.class); + router.attach(ImportResource.PATH, ImportResource.class); + router.attach(CreateUserResource.PATH, CreateUserResource.class); + router.attach(ListUsersResource.PATH, ListUsersResource.class); + router.attach(UserResource.PATH, UserResource.class); + router.attach(FindUserResource.PATH, FindUserResource.class); + router.attach(CreateCollectionResource.PATH, CreateCollectionResource.class); + router.attach(ListCollectionsResource.PATH, ListCollectionsResource.class); + router.attach(CollectionResource.PATH, CollectionResource.class); + router.attach(CollectionOutResource.PATH, CollectionOutResource.class); + + /* register any additional services */ + final Map> restServices = this.database.getRestServices(); + for (final Entry> entry : restServices.entrySet()) + router.attach(entry.getKey(), entry.getValue()); return router; } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : +} \ No newline at end of file diff -r e4dd898063a2 -r 8d11d6a17f3b artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/Standalone.java --- a/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/Standalone.java Thu Jun 04 19:40:29 2020 +0200 +++ b/artifact-database/src/main/java/org/dive4elements/artifactdatabase/rest/Standalone.java Wed Jul 15 11:53:27 2020 +0200 @@ -89,6 +89,12 @@ listen = XMLUtils.xpathString(document, LISTEN_INTERFACE, null); maxThreads = XMLUtils.xpathString(document, MAX_THREADS, null); } + + @Override + public String getServerAddress() { + String host = (this.listen == null || this.listen.trim().length() == 0 ) ? "localhost" : this.listen; + return String.format("http://%s:%d", host, this.port); + } protected Server createServer() { return listen != null && listen.length() > 0 diff -r e4dd898063a2 -r 8d11d6a17f3b artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/Config.java --- a/artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/Config.java Thu Jun 04 19:40:29 2020 +0200 +++ b/artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/Config.java Wed Jul 15 11:53:27 2020 +0200 @@ -8,22 +8,22 @@ package org.dive4elements.artifacts.common.utils; +import java.io.BufferedInputStream; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; import javax.xml.namespace.QName; - import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; - import javax.xml.xpath.XPathConstants; import org.apache.log4j.Logger; - import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; - import org.xml.sax.SAXException; /** @@ -33,8 +33,7 @@ * * @author Sascha L. Teichmann */ -public final class Config -{ +public final class Config { private static Logger logger = Logger.getLogger(Config.class); /** @@ -46,22 +45,19 @@ * Default path to the configuration directory if none * was specified by the CONFIG_DIR system property. */ - public static final File CONFIG_DIR_DEFAULT = - new File(new File(System.getProperty("user.home", - System.getProperty("user.dir", "."))), ".artifactdb"); + public static final File CONFIG_DIR_DEFAULT = new File(new File(System.getProperty("user.home", System.getProperty("user.dir", "."))), ".artifactdb"); /** * Name of the central configuration XML file. */ - public static final String CONFIG_FILE = "conf.xml"; + public static final String CONFIG_FILE = "conf.xml"; /** * Name of the configuration filename alias to be use * within the configuration. This alias is replaced by * the real path. */ - public static final String CONFIG_DIR_PLACEHOLDER = - "${artifacts.config.dir}"; + public static final String CONFIG_DIR_PLACEHOLDER = "${artifacts.config.dir}"; private static Document config; @@ -70,6 +66,7 @@ /** * Singleton access to the central XML configuration document. + * * @return The central XML configuration document. */ public static synchronized final Document getConfig() { @@ -79,18 +76,38 @@ return config; } + public static Properties loadProperties(final String CONFIG_FILE_LOCAL, final File configDir) throws IOException { + final File configFile = new File(configDir, CONFIG_FILE_LOCAL); + + InputStream reader = null; + try { + reader = new BufferedInputStream(new FileInputStream(configFile)); + + final Properties properties = new Properties(); + properties.load(reader); + return properties; + } finally { + try { + if (reader != null) + reader.close(); + } + catch (final IOException e1) { + e1.printStackTrace(); + } + } + } + /** * Returns the path to the configuartion directory. If a path * was specified via the CONFIG_DIR system property this one * is used. Else it falls back to default configuration path. + * * @return The path to the configuartion directory. */ public static File getConfigDirectory() { - String configDirString = System.getProperty(CONFIG_DIR); + final String configDirString = System.getProperty(CONFIG_DIR); - File configDir = configDirString != null - ? new File(configDirString) - : CONFIG_DIR_DEFAULT; + File configDir = configDirString != null ? new File(configDirString) : CONFIG_DIR_DEFAULT; if (!configDir.isDirectory()) { logger.warn("'" + configDir + "' is not a directory."); @@ -101,42 +118,57 @@ } /** + * returns the path to modules-config, which is a subfolder of config + */ + public static File getModulesConfigDirectory() { + + final File configDir = getConfigDirectory(); + final File modulesCfgFile = new File(configDir, "modules"); + + if (!modulesCfgFile.isDirectory()) { + logger.warn("'" + modulesCfgFile + "' is not a directory."); + return CONFIG_DIR_DEFAULT; // or null? + } + return modulesCfgFile; + } + + /** * Replaces the CONFIG_DIR_PLACEHOLDER alias with the real path * of the configuration directory. - * @param path The path containing the CONFIG_DIR_PLACEHOLDER placeholder. + * + * @param path + * The path containing the CONFIG_DIR_PLACEHOLDER placeholder. * @return The path where the CONFIG_DIR_PLACEHOLDER placeholders are - * replaced by the real path name. + * replaced by the real path name. */ - public static String replaceConfigDir(String path) { - String configDir = getConfigDirectory().getAbsolutePath(); + public static String replaceConfigDir(final String path) { + final String configDir = getConfigDirectory().getAbsolutePath(); return path.replace(CONFIG_DIR_PLACEHOLDER, configDir); } private static Document loadConfig() { - File configDir = getConfigDirectory(); + final File configDir = getConfigDirectory(); - File file = new File(configDir, CONFIG_FILE); + final File file = new File(configDir, CONFIG_FILE); if (!file.canRead() && !file.isFile()) { - logger.error("Cannot read config file '" - + file + "'."); + logger.error("Cannot read config file '" + file + "'."); return null; } try { - DocumentBuilderFactory factory = - DocumentBuilderFactory.newInstance(); + final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(false); // XXX: This may change in future. return factory.newDocumentBuilder().parse(file); } - catch (SAXException se) { + catch (final SAXException se) { logger.error(se.getLocalizedMessage(), se); } - catch (ParserConfigurationException pce) { + catch (final ParserConfigurationException pce) { logger.error(pce.getLocalizedMessage(), pce); } - catch (IOException ioe) { + catch (final IOException ioe) { logger.error(ioe.getLocalizedMessage()); } @@ -146,131 +178,152 @@ /** * Convenience method to search within a given document tree via XPath. * See {@link XMLUtils#xpath(Object, String, QName) } for details. - * @param root The object which is used as the root of the tree to - * be searched in. - * @param query The XPath query. - * @param returnType The type of the result. + * + * @param root + * The object which is used as the root of the tree to + * be searched in. + * @param query + * The XPath query. + * @param returnType + * The type of the result. * @return The result of type 'returnTyp' or null if something went - * wrong during XPath evaluation. + * wrong during XPath evaluation. */ - public static final Object getXPath( - Object root, String query, QName returnType - ) { + public static final Object getXPath(final Object root, final String query, final QName returnType) { return XMLUtils.xpath(root, query, returnType); } /** * Convenience method to search within the central configuration via XPath. * See {@link XMLUtils#xpath(Object, String, QName) } for details. - * @param query The XPath query. - * @param returnType The type of the result. + * + * @param query + * The XPath query. + * @param returnType + * The type of the result. * @return The result of type 'returnTyp' or null if something went - * wrong during XPath evaluation. + * wrong during XPath evaluation. */ - public static final Object getXPath(String query, QName returnType) { + public static final Object getXPath(final String query, final QName returnType) { return XMLUtils.xpath(getConfig(), query, returnType); } /** * Convenience method to search for a node list within the central * configuation document via XPath. - * @param query The XPath query. + * + * @param query + * The XPath query. * @return The queried node list or null if something went - * wrong during XPath evaluation. + * wrong during XPath evaluation. */ - public static final NodeList getNodeSetXPath(String query) { - return (NodeList)getXPath(query, XPathConstants.NODESET); + public static final NodeList getNodeSetXPath(final String query) { + return (NodeList) getXPath(query, XPathConstants.NODESET); } /** * Convenience method to search for a node within the central * configuation document via XPath. - * @param query The XPath query. + * + * @param query + * The XPath query. * @return The queried node or null if something went - * wrong during XPath evaluation. + * wrong during XPath evaluation. */ - public static final Node getNodeXPath(String query) { - return (Node)getXPath(query, XPathConstants.NODE); + public static final Node getNodeXPath(final String query) { + return (Node) getXPath(query, XPathConstants.NODE); } /** * Convenience method to search for a string within the central * configuation document via XPath. - * @param xpath The XPath query. + * + * @param xpath + * The XPath query. * @return The queried string or null if something went - * wrong during XPath evaluation. + * wrong during XPath evaluation. */ - public static final String getStringXPath(String xpath) { + public static final String getStringXPath(final String xpath) { return getStringXPath(xpath, null); } /** * Convenience method to search for a string within the central * configuation document via XPath. - * @param query The XPath query. - * @param def The string to be returned if the search has no results. + * + * @param query + * The XPath query. + * @param def + * The string to be returned if the search has no results. * @return The queried string or the default value if something went - * wrong during XPath evaluation. + * wrong during XPath evaluation. */ - public static final String getStringXPath(String query, String def) { - String s = (String)getXPath(query, XPathConstants.STRING); - return s == null || s.length() == 0 - ? def - : s; + public static final String getStringXPath(final String query, final String def) { + final String s = (String) getXPath(query, XPathConstants.STRING); + return s == null || s.length() == 0 ? def : s; } /** * Convenience method to search for a node list within a given tree * via XPath. - * @param root The root of the tree to be searched in. - * @param query The XPath query. + * + * @param root + * The root of the tree to be searched in. + * @param query + * The XPath query. * @return The queried node list or null if something went - * wrong during XPath evaluation. + * wrong during XPath evaluation. */ - public static final NodeList getNodeSetXPath(Object root, String query) { - return (NodeList)getXPath(root, query, XPathConstants.NODESET); + public static final NodeList getNodeSetXPath(final Object root, final String query) { + return (NodeList) getXPath(root, query, XPathConstants.NODESET); } /** * Convenience method to search for a node within a given tree * via XPath. - * @param root The root of the tree to be searched in. - * @param query The XPath query. + * + * @param root + * The root of the tree to be searched in. + * @param query + * The XPath query. * @return The queried node or null if something went - * wrong during XPath evaluation. + * wrong during XPath evaluation. */ - public static final Node getNodeXPath(Object root, String query) { - return (Node)getXPath(root, query, XPathConstants.NODE); + public static final Node getNodeXPath(final Object root, final String query) { + return (Node) getXPath(root, query, XPathConstants.NODE); } /** * Convenience method to search for a string within a given tree * via XPath. - * @param root The root of the tree to be searched in. - * @param xpath The XPath query. + * + * @param root + * The root of the tree to be searched in. + * @param xpath + * The XPath query. * @return The queried string or null if something went - * wrong during XPath evaluation. + * wrong during XPath evaluation. */ - public static final String getStringXPath(Object root, String xpath) { + public static final String getStringXPath(final Object root, final String xpath) { return getStringXPath(root, xpath, null); } /** * Convenience method to search for a string within a given tree * via XPath. - * @param root The root of the tree to be searched in. - * @param query xpath The XPath query. - * @param def The string to be returned if the search has no results. + * + * @param root + * The root of the tree to be searched in. + * @param query + * xpath The XPath query. + * @param def + * The string to be returned if the search has no results. * @return The queried string or the default value if something went - * wrong during XPath evaluation. + * wrong during XPath evaluation. */ - public static final String getStringXPath( - Object root, String query, String def - ) { - String s = (String)getXPath(root, query, XPathConstants.STRING); - return s == null || s.length() == 0 - ? def - : s; + public static final String getStringXPath(final Object root, final String query, final String def) { + final String s = (String) getXPath(root, query, XPathConstants.STRING); + return s == null || s.length() == 0 ? def : s; } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r e4dd898063a2 -r 8d11d6a17f3b artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/DateUtils.java --- a/artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/DateUtils.java Thu Jun 04 19:40:29 2020 +0200 +++ b/artifacts-common/src/main/java/org/dive4elements/artifacts/common/utils/DateUtils.java Wed Jul 15 11:53:27 2020 +0200 @@ -17,14 +17,120 @@ * * @return the year as integer or -1 if date is empty. */ - public static int getYearFromDate(Date date) { + public static int getYearFromDate(final Date date) { if (date == null) { return -1; } - Calendar cal = Calendar.getInstance(); + final Calendar cal = Calendar.getInstance(); cal.setTime(date); return cal.get(Calendar.YEAR); } + + /** + * Gets the abfluss year (1.11. - 31.10.) a date belongs to + * + * @return the abfluss year, or -1 + */ + public static int getAbflussYearFromDate(final Date date) { + if (date == null) + return -1; + final Calendar cal = Calendar.getInstance(); + cal.setTime(getAbflussYear(date)[1]); + return cal.get(Calendar.YEAR); + } + + /** + * Gets the date range of the abfluss year (1.11. - 31.10.) a date belongs to + * + * @return [abfluss year start date, abfluss year end date], or null + */ + public static Date[] getAbflussYear(final Date date) { + if (date == null) + return null; + final Calendar cal = Calendar.getInstance(); + cal.setTime(date); + final int qYear = (cal.get(Calendar.MONTH) >= 10) ? cal.get(Calendar.YEAR) + 1 : cal.get(Calendar.YEAR); + return getAbflussYear(qYear); + } + + /** + * Gets the date range of the abfluss year (1.11. - 31.10.) a date belongs to + * + * @return [abfluss year start date, abfluss year end date], or null + */ + public static Date[] getAbflussYear(final int year) { + final Calendar calStart = Calendar.getInstance(); + calStart.clear(); + calStart.set(year - 1, 10, 1, 0, 0, 0); + final Calendar calEnd = Calendar.getInstance(); + calEnd.clear(); + calEnd.set(year, 9, 31, 23, 59, 59); + return new Date[] { calStart.getTime(), calEnd.getTime() }; + } + + /** + * Gets the date range of the abfluss year following a date, or that of the date itself if it's a nov-1 + * + * @return [abfluss year start date, abfluss year end date], or null + */ + public static Date[] getNextAbflussYear(final Date date) { + if (date == null) + return null; + final Calendar cal = Calendar.getInstance(); + cal.setTime(date); + final int nextQYear = cal.get(Calendar.YEAR) + 1; + switch (cal.get(Calendar.MONTH)) { + case 10: + if (cal.get(Calendar.DAY_OF_MONTH) >= 2) + return getAbflussYear(nextQYear + 1); + break; + case 11: + return getAbflussYear(nextQYear + 1); + default: + break; + } + return getAbflussYear(nextQYear); + } + + /** + * Gets the date range of the abfluss year preceeding a date, or that of the date itself if it's a oct-31 + * + * @return [abfluss year start date, abfluss year end date], or null + */ + public static Date[] getPreviousAbflussYear(final Date date) { + if (date == null) + return null; + final Calendar cal = Calendar.getInstance(); + cal.setTime(date); + final int previousQYear = cal.get(Calendar.YEAR); + switch (cal.get(Calendar.MONTH)) { + case 10: + case 11: + break; + case 9: + if (cal.get(Calendar.DAY_OF_MONTH) <= 30) + return getAbflussYear(previousQYear - 1); + break; + default: + return getAbflussYear(previousQYear - 1); + } + return getAbflussYear(previousQYear); + } + + /** + * Gets the date of the new year's day following a date, or the date itself with 0-time if it's a jan-1 + * + * @return a newyear's date, or null + */ + public static Date getNextNewYear(final Date date) { + if (date == null) + return null; + final Calendar cal = Calendar.getInstance(); + cal.setTime(date); + final int offset = (cal.get(Calendar.DAY_OF_YEAR) == 1) ? 0 : 1; + cal.set(cal.get(Calendar.YEAR) + offset, 0, 1, 0, 0, 0); + return cal.getTime(); + } } diff -r e4dd898063a2 -r 8d11d6a17f3b artifacts/src/main/java/org/dive4elements/artifacts/ArtifactDatabase.java --- a/artifacts/src/main/java/org/dive4elements/artifacts/ArtifactDatabase.java Thu Jun 04 19:40:29 2020 +0200 +++ b/artifacts/src/main/java/org/dive4elements/artifacts/ArtifactDatabase.java Wed Jul 15 11:53:27 2020 +0200 @@ -14,6 +14,7 @@ import org.w3c.dom.Document; import java.util.Date; +import java.util.Map; /** * Interface of an artifact managing database. @@ -296,5 +297,10 @@ throws ArtifactDatabaseException; String findArtifactUser(String artifactIdentifier); + + String getServerAddress(); + + /** an additional list of rest services (path and implementing class) that should be registered */ + Map> getRestServices(); } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :