# HG changeset patch # User Thomas Arendsen Hein # Date 1348827312 -7200 # Node ID d01e9f6a3dc1503d98dc4e2a2bfe7a990c8de1ab # Parent 2c2981e53d4e449de25b975d919c09799aa854e4# Parent c53ec9fdc75845eb166b9a8556b4b40ab7bc53a2 dummy merge for repo head diff -r c53ec9fdc758 -r d01e9f6a3dc1 ChangeLog --- a/ChangeLog Mon Sep 19 13:55:26 2011 +0000 +++ b/ChangeLog Fri Sep 28 12:15:12 2012 +0200 @@ -1,3 +1,624 @@ +2012-09-26 Björn Ricks + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/AbstractState.java: + New method addOutput to allow subclasses to add Output object manually. + +2012-09-17 Ingo Weinzierl + + Tagged RELEASE 2.9.1 + +2012-09-10 Sascha L. Teichmann + + * artifacts/pom.xml, pom.xml: source 1.5 -> 1.6 + (@Override annotations for interface implementations is 1.6). + +2012-09-07 Björn Ricks + + * artifact-database/src/main/resources/sql/org-h2-driver.properties, + artifact-database/src/main/resources/sql/org-postgresql-driver.properties: + Fix queries for finding a user. + +2012-09-07 Ingo Weinzierl + + Tagged RELEASE 2.9 + +2012-08-30 Felix Wolfsteller + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultSection.java: + Use LinkedHashMap to keep insertion order of attributes. + +2012-08-27 Christian Lins + + * artifact-database/src/main/java/de/intevation/artifactdatabase/ArtifactDatabaseImpl.java, + artifacts/src/main/java/de/intevation/artifacts/CallContext.java: + Fix for NPE on empty user database. + +2012-08-24 Björn Ricks + + * artifact-database/src/main/java/de/intevation/artifactdatabase/rest/RestApp.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/rest/FindUserResource.java: + Add REST service to be able to find a user by its account name. + +2012-08-24 Björn Ricks + + * artifact-database/src/main/java/de/intevation/artifactdatabase/ArtifactDatabaseImpl.java, + artifacts/src/main/java/de/intevation/artifacts/ArtifactDatabase.java: + Implement findUser method. The findUser method in ArtifactDatabase + converts a User object into its XML representation. + +2012-08-24 Björn Ricks + + * artifact-database/src/main/java/de/intevation/artifactdatabase/Backend.java, + artifact-database/src/main/resources/sql/org-h2-driver.properties, + artifact-database/src/main/resources/sql/org-postgresql-driver.properties: + Implement method to find/get a user by its account name. + +2012-08-23 Björn Ricks + + * artifact-database/src/main/java/de/intevation/artifactdatabase/ArtifactDatabaseImpl.java: + Also add the account information when listing users. + +2012-08-23 Björn Ricks + + * artifact-database/src/main/java/de/intevation/artifactdatabase/ArtifactDatabaseImpl.java: + Add account information to createUser + +2012-08-23 Björn Ricks + + * artifact-database/src/main/java/de/intevation/artifactdatabase/Backend.java: + Read the account information from the database. + +2012-08-23 Björn Ricks + + * artifact-database/src/main/java/de/intevation/artifactdatabase/LazyBackendUser.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultUserFactory.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultUser.java: + Extend user class implementations to handle account information. + +2012-08-23 Björn Ricks + + * artifacts/src/main/java/de/intevation/artifacts/UserFactory.java, + artifacts/src/main/java/de/intevation/artifacts/User.java: + Extend user interfaces to handle account information. + +2012-08-23 Björn Ricks + + * artifact-database/src/main/resources/sql/org-h2-driver.properties, + artifact-database/src/main/resources/sql/org-postgresql-driver.properties: + Update sql user queries to add the account column. + +2012-08-23 Björn Ricks + + * artifact-database/doc/schema-pg.sql, + artifact-database/doc/schema-h2.sql: + Add a account column to the users table. + +2012-07-29 Sascha L. Teichmann + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/FacetActivity.java: + Refactored registry to use a Chain-of-responsibility pattern. This allows + de-centralized facet activity treatment like in the facet producing states. + +2012-07-29 Sascha L. Teichmann + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/FacetActivity.java: + Made Registry.getInstance() access static. + +2012-07-29 Sascha L. Teichmann + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/FacetActivity.java: + New. Implementors of this interface can decide if a facet should be initially + active or not. Contains a registry singleton. + +2012-07-27 Ingo Weinzierl + + Tagged trunk as '2.8.1' + +2012-07-19 Sascha L. Teichmann + + * artifacts-common/src/main/java/de/intevation/artifacts/common/utils/StringUtils.java: + Added concat() to join two String arrays. + +2012-07-17 Felix Wolfsteller + + * artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactCollection.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/state/AbstractState.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/AbstractCallContext.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactCollectionFactory.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/transition/TransitionEngine.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/ProtocolUtils.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/DatabaseCleaner.java: + Doc fixes. + +2012-07-16 Ingo Weinzierl + + Tagged trunk as '2.8' + +2012-07-19 Sascha L. Teichmann + + * artifacts-common/src/main/java/de/intevation/artifacts/common/utils/StringUtils.java: + Added concat() to join two String arrays. + +2012-07-17 Felix Wolfsteller + + * artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactCollection.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/state/AbstractState.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/AbstractCallContext.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactCollectionFactory.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/transition/TransitionEngine.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/ProtocolUtils.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/DatabaseCleaner.java: + Doc fixes. + +2012-07-16 Ingo Weinzierl + + Tagged trunk as '2.8' + +2012-07-15 Sascha L. Teichmann + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultSettings.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultSection.java, + artifacts/src/main/java/de/intevation/artifacts/DataProvider.java, + artifacts/src/main/java/de/intevation/artifacts/ArtifactFactory.java: + Removed same package imports. + +2012-07-03 Sascha L. Teichmann + + * artifacts-common/src/main/java/de/intevation/artifacts/common/utils/StringUtils.java: + Added contains(String needle, String [] haystack) method. + +2012-07-03 Ingo Weinzierl + + * artifact-database/.settings/org.eclipse.jdt.core.prefs: Removed from + version control (Eclipse configurations should not be in SVN!). + +2012-02-26 Felix Wolfsteller + + * artifact-database/src/main/java/de/intevation/artifactdatabase/ArtifactDatabaseImpl.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/rest/UserResource.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactContext.java: + Cosmetics, doc. + +2012-06-23 Sascha L. Teichmann + + * artifact-database/src/main/java/de/intevation/**/*.java: + Removed trailing whitespace. + +2012-06-05 Ingo Weinzierl + + * artifact-database/src/main/java/de/intevation/artifactdatabase/Backend.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/DatabaseCleaner.java: + Added some more debug output during the process of removing Artifacts + and Collections with the DatabaseCleaner. + +2012-06-01 Sascha L. Teichmann + + * artifacts-common/src/main/java/de/intevation/artifacts/common/utils/XMLUtils.java: + Remove extra from the XML generated by JSON lists containing only + objects. + +2012-05-27 Ingo Weinzierl + + Tagged trunk as '2.7' + +2012-05-18 Ingo Weinzierl + + * artifacts-common/src/main/java/de/intevation/artifacts/common/utils/DateUtils.java: + New utility class that provides functions that helps working with dates. + +2012-05-15 Ingo Weinzierl + + * artifacts-common/src/main/java/de/intevation/artifacts/common/model/KVP.java: + New class to store generic keys and values. + +2012-05-07 Raimund Renkert + + * artifacts-common/src/main/java/de/intevation/artifacts/common/utils/XMLUtils.java: + Added method to create a document from string. + +2012-05-03 Ingo Weinzierl + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/State.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/state/AbstractState.java: + Defined and implemented a method getHelpText(). + +2012-05-02 Sascha L. Teichmann + + * artifacts-common/src/main/java/de/intevation/artifacts/common/utils/XSLTransformer.java: + Widen parameters to store more than strings. + +2012-04-27 Sascha L. Teichmann + + * artifacts-common/src/main/java/de/intevation/artifacts/common/utils/JSON.java: + Added toJSONString() method. + + * artifacts-common/src/main/java/de/intevation/artifacts/common/utils/XMLUtils.java: + Fixed building XML documents from JSON strings. + +2012-04-25 Raimund Renkert + + * artifacts-common/src/main/java/de/intevation/artifacts/common/utils/FileTools.java: + Added method to extract zip archives to a specified directory. + +2012-04-19 Sascha L. Teichmann + + * artifacts-common/src/main/java/de/intevation/artifacts/common/utils/XSLTransformer.java: + New. Added new XSLT processor similiar to old GNV one. + +2012-04-18 Sascha L. Teichmann + + * artifacts-common/src/main/java/de/intevation/artifacts/common/utils/JSON.java: + New. JSON parser from Artefact Server NG (which relies on JSON more heavily). + + * artifacts-common/src/main/java/de/intevation/artifacts/common/utils/XMLUtils.java: + Added method to convert JSON to XML. This is needed by the client which + internally uses JSON to talk to the server which services only understands + XML atm. + +2012-04-04 Sascha L. Teichmann + + Modified services so that they are now able to return more than just + XML documents. Needed if you want to return e.g. a PNG image from a service. + + * artifacts/src/main/java/de/intevation/artifacts/Service.java: + A service now returns a tuple (data, MIME type). + + * artifacts/src/main/java/de/intevation/artifacts/ArtifactDatabase.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/ArtifactDatabaseImpl.java: + Adjusted calls. + + * artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultService.java: + Returns a DefaultService.Output by default. + + * artifact-database/src/main/java/de/intevation/artifactdatabase/XMLService.java: New. + Convenience sub class if DefaultService to produce XML documents. Old + Services should derive from this class now to main compatibility. + + * artifact-database/src/main/java/de/intevation/artifactdatabase/rest/ServiceResource.java: + Adjusted to handle the new Output tuples. + + * artifact-database/src/main/java/de/intevation/artifactdatabase/rest/ByteArrayRepresentation.java: + New. Wraps a byte array as a Restlet representation. + +2012-03-30 Ingo Weinzierl + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultOutput.java: + Avoid adding duplicated facets into the output in addFacet(). + +2012-02-10 Felix Wolfsteller + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/Facet.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/state/ArtifactAndFacet.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultFacet.java: + Pass context when asking facet for keys to write on 'blackboard'. + +2012-02-09 Ingo Weinzierl + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/ArtifactAndFacet.java: + Added a method setFacetDescription() which sets an alternative + description for the facet. getFacetDescription() will now return the + Facet's descritpion itself if no alternative description has been set; + otherwise the alternative description. + +012-02-09 Sascha L. Teichmann + + * artifacts-common/src/main/java/de/intevation/artifacts/common/utils/StringUtils.java(join): + Added static method to join strings with a separator. + +012-01-30 Sascha L. Teichmann + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/ArtifactAndFacet.java: + Added Override annotations. + +2012-01-30 Ingo Weinzierl + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/StateEngine.java: + Added a method that returns a StateData objects of a specific Artifact + based on the Artifact's StateData's name. + +2012-01-30 Ingo Weinzierl + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/AbstractState.java: + Bugfix: search for StateData objects by name only the State has + StateData objects set. + +2012-01-30 Ingo Weinzierl + + * artifacts-common/src/main/java/de/intevation/artifacts/common/utils/ClientProtocolUtils.java: + Added methods to extract the default value for a min and max item. + +2012-01-18 Ingo Weinzierl + + * artifacts-common/src/main/java/de/intevation/artifacts/common/utils/ClientProtocolUtils.java: + Added methods to retrieve the min and max values of a data item. + +2012-01-16 Sascha L. Teichmann + + * artifacts-common/src/main/java/de/intevation/artifacts/common/utils/FileTools.java: + Replaced legacy java.util.Stack with java.util.Deque. + +2012-01-16 Felix Wolfsteller + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/AbstractState.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultFacet.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifact.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactCollectionFactory.java, + artifacts-common/src/main/java/de/intevation/artifacts/common/utils/ClientProtocolUtils.java, + artifacts-common/src/main/java/de/intevation/artifacts/common/utils/XMLUtils.java: + Cosmetics. + +2012-01-11 Sascha L. Teichmann + + * artifact-database/src/main/java/de/intevation/artifactdatabase/AbstractCallContext.java: + Instance vars customValues and dataProviders are now of type Map + and not HashMap. + +2012-01-09 Ingo Weinzierl + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/State.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/state/AbstractState.java: + Added the owner Artifact as further parameter to initialize(). + +2012-01-09 Ingo Weinzierl + + * artifacts-common/src/main/java/de/intevation/artifacts/common/utils/FileTools.java: + Added new functions to copy files (copyFile()) and to copy directories + (copyDirectory()). + +2012-01-09 Ingo Weinzierl + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/State.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/state/AbstractState.java: + Added an initialize() method which might be used to initialize the State + based on model Artifact. + +2011-12-16 Felix Wolfsteller + + * artifact-database/src/main/java/de/intevation/artifactdatabase/AbstractCallContext.java: + (getDataProvider): Never return null. + +2011-12-16 Ingo Weinzierl + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/Output.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultOutput.java: + Added a new method setFacets(List) to replace an existing list of + Facets. + +2011-12-14 Ingo Weinzierl + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/Attribute.java: + Added a setValue(Object) method and modified the signature of toXML() + which now returns a Node. + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultAttribute.java: + New. A default implementation of Attribute. + +2011-12-14 Ingo Weinzierl + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/Settings.java: + Added a removeSection(Section) method. + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/Section.java: + Improved the interface to allow section having subsections. Therefore, + addSubsection(Section), getSubsectionCount() and getSubsection(int) have + been added. In addition, a getId() method has been added which is used + in toXML() to create a new DOM Node. The Node name is the result of + getId(). + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultSettings.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultSection.java: + Default implementations for Settings and Section. + +2011-12-14 Ingo Weinzierl + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/Settings.java: + An interface that describes a flat API for specifying settings for + something. A Settings object can store one or more Section instances and + defines a toXML() operation that should append a XML representation of + itself to a given parent Node. + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/Section.java: + This interface is used to describe an API for storing and retrieving + Attribute objects. Just as the Settings interface, it defines a toXML() + operation that should append a XML representation of itself to a given + parent Node. + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/Attribute.java: + The interface for concrete attributes in a Section instance. An Attribute + is the placed on the lowest level of the Settings hierachy and should be + used to save concrete key value pairs. Even the Attribute defines the + toXML() operation described above. + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/Output.java: + Added a getSettings() and setSettings(Settings) operation. + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultOutput.java: + A DefaultOutput is now able to store a Settings instance. It implements + getSettings() and setSettings(Settings) defined in the Output interface. + +2011-12-09 Felix Wolfsteller + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/Facet.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultFacet.java: + (getDataProviderKeys): Added parameter artifact. + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/ArtifactAndFacet.java: + Pass artifact to changed getDataProviderKeys of Facet. + + * artifact-database/src/main/java/de/intevation/artifactdatabase/AbstractCallContext.java: + (getDataProvider): Never return null, empty list instead. + +2011-11-30 Felix Wolfsteller + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/ArtifactAndFacet.java + (getFacetDescription): New, access facets description. + +2011-11-30 Felix Wolfsteller + + Added convenienve bundle of artifact and facet that implements + DataProvider. This will help keeping things together in the upcoming + inter-facet pre-rendering communication ('blackboard') phase. + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/ArtifactAndFacet.java: + New class, keeping together an artifact and a facet (thus, should + only have a short live span). Only implementation of the new + DataProvider interface. + +2011-11-30 Felix Wolfsteller + + Extended CallContext to also act as a blackboard/service broker. + + * artifacts/src/main/java/de/intevation/artifacts/CallContext.java + (getDataProvider,registerDataProvider): New functions to register/ + consume data providers. + + * artifact-database/src/main/java/de/intevation/artifactdatabase/AbstractCallContext.java + (getDataProvider,registerDataProvider): Implemented. + +2011-11-30 Felix Wolfsteller + + Added DataProvider interface that defines api for inter-facet + communication. + + * artifacts/src/main/java/de/intevation/artifacts/DataProvider.java: + New interface to prepare inter-facet pre-rendering communication + phase ('blackboard'). + +2011-11-30 Felix Wolfsteller + + Prepare inter-facet pre-rendering communication ('blackboard') phase. + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/Facet.java + (getDataProviderKeys,provideBlackboardData): Extended interface to + allow easy integration of blackboard mechanism (inter-facet + pre-rendering communication). + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultFacet.java + (getDataProviderKeys,provideBlackboardData): Trivial implementation. + The DefaultFacet will not talk to other facets during inter-facet + pre-rendering ("blackboard") phase. Cosmetics, docs. + +2011-11-21 Ingo Weinzierl + + * artifacts-common/src/main/java/de/intevation/artifacts/common/utils/XMLUtils.java: + Changed Ingo's last commit to a more conservative notation (no auto-boxing). + Strangely the flys-client does not compile for me with the auto-boxed + syntax with OpenJDK! + +2011-11-21 Ingo Weinzierl + + * artifacts-common/src/main/java/de/intevation/artifacts/common/utils/XMLUtils.java: + Added a method that allows to specify if the document needs to be + namespace aware or not while parsing from InputStream. + +2011-11-07 Ingo Weinzierl + + * artifact-database/src/main/java/de/intevation/artifactdatabase/ArtifactDatabaseImpl.java, + artifact-database/src/main/java/de/intevation/artifactdatabase/FactoryBootstrap.java: + Enabled "post-describe" hooks for the Artifact's describe operation. + +2011-10-28 Felix Wolfsteller + + Let StateEngine compute a compatibiliy matrix based on given State + IDs. + + * artifact-database/src/main/java/de/intevation/artifactdatabase/state/StateEngine.java + (getCompatibleFacets): New. Compute output/facet compatibility + matrix based on given states. + +2011-10-21 Ingo Weinzierl + + * artifact-database/src/main/resources/sql/org-h2-driver.properties: + Bugfix: added missing bracket to an sql statement. + +2011-10-20 Sascha L. Teichmann + + * artifact-database/src/main/java/de/intevation/artifactdatabase/Backend.java(getMasterArtifact): + Limit result set to one row. + +2011-10-19 Felix Wolfsteller + + Fix accidentally corruptd key to sql statement. + + * artifact-database/src/main/java/de/intevation/artifactdatabase/Backend.java: + Fix key. + +2011-10-19 Felix Wolfsteller + + Add backend and db functionality query artifact which is belongs to + a collection the longest (not neccessary the longest artifact itself). + + * artifact-database/src/main/java/de/intevation/artifactdatabase/ArtifactDatabaseImpl.java + (getCollectionsMasterArtifact): New. Access master artifact for + given collection (masterartifact defined as artifact which belongs + to the collection the longest). + + * artifacts/src/main/java/de/intevation/artifacts/ArtifactDatabase.java + (getCollectionsMasterArtifact): New (extended interface). + + * artifact-database/src/main/java/de/intevation/artifactdatabase/Backend.java + (getMasterArtifact): New, get UUID of oldest artifact which belongs to + collection the longest. + + * artifact-database/src/main/resources/sql/org-h2-driver.properties, + artifact-database/src/main/resources/sql/org-postgresql-driver.properties: + Added SQL query to get list of artifacts in collection sorted by the + entry date. + +2011-10-17 Sascha L. Teichmann + + * artifacts-common/src/main/java/de/intevation/artifacts/common/utils/StringUtils.java(toUpperCase): + Added static method to convert an array of string to their uppercase counterparts. + +2011-10-13 Felix Wolfsteller + + * artifacts-common/src/main/java/de/intevation/artifacts/common/utils/ClientProtocolUtils.java: + (newRemoveArtifactDocument): New, create a "remove artifact" document. + Cosmetics, docs. + +2011-10-13 Felix Wolfsteller + + * artifact-database/src/main/resources/sql/org-h2-driver.properties, + artifact-database/src/main/resources/sql/org-postgresql-driver.properties: + Fix SQL typo. + +2011-10-10 Felix Wolfsteller + + * artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactCollection.java: + Cosmetics, (shortened jdoc comments). + + * artifacts-common/src/main/java/de/intevation/artifacts/common/utils/XMLUtils.java: + Cosmetics, (shortened jdoc comments). Also, removed + toString(Element), instead fixed toString(Node) - Node is + superinterface of Element. + +2011-10-07 Sascha L. Teichmann + + Fixed flys/issue255 + + * artifact-database/src/main/java/de/intevation/artifactdatabase/db/DBConnection.java(getDataSource()): + Serialized the loading of database drivers. + +2011-09-23 Felix Wolfsteller + + Fix debug helper toString(Node). + + * artifacts-common/src/main/java/de/intevation/artifacts/common/utils/XMLUtils.java: + (toString(Node)): Fix issue with node from "wrong" document. + +2011-09-23 Felix Wolfsteller + + Added XMLUtils functions helping to debug parts of xml documents. + + * artifacts-common/src/main/java/de/intevation/artifacts/common/utils/XMLUtils.java: + (toString(Node), toString(Element): New functions returning + xml/string representations of parts of documents. + +2011-09-22 Ingo Weinzierl + + * artifact-database/src/main/java/de/intevation/artifactdatabase/ArtifactDatabaseImpl.java: + Removed useless CollectionCallContext creation (was never used). + 2011-09-19 Ingo Weinzierl Tagged RELEASE 1.4 diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/.settings/org.eclipse.jdt.core.prefs --- a/artifact-database/.settings/org.eclipse.jdt.core.prefs Mon Sep 19 13:55:26 2011 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,5 +0,0 @@ -#Tue Sep 08 09:33:09 CEST 2009 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5 -eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.source=1.5 -org.eclipse.jdt.core.compiler.compliance=1.5 diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/doc/schema-h2.sql --- a/artifact-database/doc/schema-h2.sql Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/doc/schema-h2.sql Fri Sep 28 12:15:12 2012 +0200 @@ -23,7 +23,8 @@ CREATE TABLE users ( id INT PRIMARY KEY NOT NULL, gid UUID NOT NULL UNIQUE, - name VARCHAR(256) NOT NULL UNIQUE, + name VARCHAR(256) NOT NULL, + account VARCHAR(256) NOT NULL UNIQUE, role BINARY ); diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/doc/schema-pg.sql --- a/artifact-database/doc/schema-pg.sql Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/doc/schema-pg.sql Fri Sep 28 12:15:12 2012 +0200 @@ -23,7 +23,8 @@ CREATE TABLE users ( id int PRIMARY KEY NOT NULL, gid uuid NOT NULL UNIQUE, - name VARCHAR(256) NOT NULL UNIQUE, + name VARCHAR(256) NOT NULL, + account VARCHAR(256) NOT NULL UNIQUE, role bytea ); diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/AbstractCallContext.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/AbstractCallContext.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/AbstractCallContext.java Fri Sep 28 12:15:12 2012 +0200 @@ -7,11 +7,17 @@ */ package de.intevation.artifactdatabase; +import org.apache.log4j.Logger; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; import java.util.HashMap; import de.intevation.artifacts.ArtifactDatabase; import de.intevation.artifacts.CallContext; import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.DataProvider; /** @@ -22,6 +28,8 @@ */ public abstract class AbstractCallContext implements CallContext { + Logger logger = Logger.getLogger(AbstractCallContext.class); + /** * The ArtifactDatabase instance. */ @@ -40,15 +48,20 @@ /** * Map to act like a clipboard when nesting calls like a proxy artifact. */ - protected HashMap customValues; + protected Map customValues; + + /** + * Map to act like a clipboard when nesting calls like a proxy artifact. + */ + protected Map> dataProviders; /** * The default constructor of this abstract CallContext. * + * @param artifactDatabase The artifact database. * @param action The action. * @param callMeta The CallMeta object. - * @param context The global context. */ public AbstractCallContext( ArtifactDatabaseImpl artifactDatabase, @@ -101,5 +114,41 @@ } return customValues.put(key, value); } + + /** + * Get list of DataProviders that registered for given key. + * @return list (empty list if none found, never null). + */ + public List getDataProvider(Object key) { + if (dataProviders != null) { + List list = dataProviders.get(key); + return list != null + ? list + : java.util.Collections.emptyList(); + } + return java.util.Collections.emptyList(); + } + + + /** + * Let a DataProvider register itself with given key. + * Multiple DataProvider can register under the same key. + */ + public Object registerDataProvider(Object key, DataProvider value) { + List providers = null; + if (dataProviders == null) { + dataProviders = new HashMap(); + providers = new ArrayList(); + providers.add(value); + return dataProviders.put(key, providers); + } + providers = dataProviders.get(key); + + if (providers == null) { + providers = new ArrayList(); + } + providers.add(value); + return dataProviders.put(key, providers); + } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/ArtifactDatabaseImpl.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/ArtifactDatabaseImpl.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/ArtifactDatabaseImpl.java Fri Sep 28 12:15:12 2012 +0200 @@ -197,6 +197,14 @@ public static final String XPATH_USERROLE = "/art:action/art:user/art:role"; + /** XPath to figure out the account of a new user.*/ + public static final String XPATH_USERACCOUNT = + "/art:action/art:user/art:account/@name"; + + /** XPath to figure out the account of when searching for a user .*/ + public static final String XPATH_USERACCOUNT_FIND = + "/art:action/art:account/@name"; + /** Error message if a specified user does not exist.*/ public static final String NO_SUCH_USER = "No such user"; @@ -205,6 +213,10 @@ public static final String NO_USERNAME = "Invalid username"; + /** Error message if no user account is given for user creation.*/ + public static final String NO_USERACCOUNT = + "Invalid user account name"; + // Collection constants /** @@ -444,6 +456,12 @@ */ protected List postAdvanceHooks; + /** + * Hooks that are executed after an artifact's describe() operation was + * called. + */ + protected List postDescribeHooks; + protected List lifetimeListeners; /** @@ -511,6 +529,10 @@ this.postAdvanceHooks = postAdvanceHooks; } + public void setPostDescribeHook(List postDescribeHooks) { + this.postDescribeHooks = postDescribeHooks; + } + /** * Used to extract the artifact collection factory from bootstrap. * @@ -558,6 +580,7 @@ protected void setupHooks(FactoryBootstrap bootstrap) { setPostFeedHook(bootstrap.getPostFeedHooks()); setPostAdvanceHook(bootstrap.getPostAdvanceHooks()); + setPostDescribeHook(bootstrap.getPostDescribeHooks()); } protected void setupBackendListeners(FactoryBootstrap bootstrap) { @@ -767,6 +790,8 @@ ) throws ArtifactDatabaseException { + logger.debug("ArtifactDatabaseImpl.createArtifactWithFactory " + + factoryName); ArtifactFactory factory = getArtifactFactory(factoryName); if (factory == null) { @@ -845,7 +870,16 @@ artifact); try { - return artifact.getArtifact().describe(data, cc); + Artifact art = artifact.getArtifact(); + Document res = art.describe(data, cc); + + if (postDescribeHooks != null) { + for (Hook hook: postDescribeHooks) { + hook.execute(art, cc, res); + } + } + + return res; } finally { cc.postCall(); @@ -1140,7 +1174,7 @@ return serviceNamesAndDescription; } - public Document process( + public Service.Output process( String serviceName, Document input, CallMeta callMeta @@ -1158,6 +1192,7 @@ // User API + /** Returns user(s) elements. */ public Document listUsers(CallMeta callMeta) throws ArtifactDatabaseException { @@ -1183,20 +1218,74 @@ Element root = ec.create("users"); result.appendChild(root); - for (User user: users) { - Element ue = ec.create("user"); + if(users != null) { + for (User user: users) { + Element ue = ec.create("user"); + ec.addAttr(ue, "uuid", user.identifier(), true); + ec.addAttr(ue, "name", user.getName(), true); + Element ua = ec.create("account"); + ec.addAttr(ua, "name", user.getAccount(), true); + ue.appendChild(ua); + + Document role = user.getRole(); + + if (role != null) { + ue.appendChild(result.importNode(role.getFirstChild(), true)); + } + + root.appendChild(ue); + } + } + + return result; + } + + /** Search for a user. */ + public Document findUser(Document data, CallMeta callMeta) + throws ArtifactDatabaseException + { + UserFactory factory = getUserFactory(); + + if (factory == null) { + throw new ArtifactDatabaseException(NO_SUCH_FACTORY); + } + + String account = XMLUtils.xpathString( + data, XPATH_USERACCOUNT_FIND, ArtifactNamespaceContext.INSTANCE); + + if (account == null || account.length() == 0) { + logger.warn("Can't find user without account!"); + throw new ArtifactDatabaseException(NO_USERACCOUNT); + } + + User user = backend.findUser(account, factory, context); + + Document result = XMLUtils.newDocument(); + + XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator( + result, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + Element ue = ec.create("user"); + + if (user != null) { + logger.debug(user + " user found in the backend."); + ec.addAttr(ue, "uuid", user.identifier(), true); ec.addAttr(ue, "name", user.getName(), true); + Element ua = ec.create("account"); + ec.addAttr(ua, "name", user.getAccount(), true); + ue.appendChild(ua); Document role = user.getRole(); if (role != null) { ue.appendChild(result.importNode(role.getFirstChild(), true)); } + } - root.appendChild(ue); - - } + result.appendChild(ue); return result; } @@ -1218,6 +1307,14 @@ throw new ArtifactDatabaseException(NO_USERNAME); } + String account = XMLUtils.xpathString( + data, XPATH_USERACCOUNT, ArtifactNamespaceContext.INSTANCE); + + if (account == null || account.length() == 0) { + logger.warn("User without account not accepted!"); + throw new ArtifactDatabaseException(NO_USERACCOUNT); + } + Node tmp = (Node) XMLUtils.xpath( data, XPATH_USERROLE, @@ -1234,7 +1331,7 @@ User newUser = null; try { - newUser = backend.createUser(name, role, userFactory, context); + newUser = backend.createUser(name, account, role, userFactory, context); } catch (Exception e) { logger.error(e.getMessage(), e); @@ -1287,6 +1384,64 @@ // Collection API + public Document getCollectionsMasterArtifact( + String collectionId, + CallMeta meta) + throws ArtifactDatabaseException + { + Document result = XMLUtils.newDocument(); + String masterUUID = backend.getMasterArtifact(collectionId); + + XMLUtils.ElementCreator ec = new XMLUtils.ElementCreator( + result, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + ArtifactCollectionFactory acf = getArtifactCollectionFactory(); + + if (acf == null) { + throw new ArtifactDatabaseException(NO_SUCH_FACTORY); + } + + UserFactory uf = getUserFactory(); + if (uf == null) { + throw new ArtifactDatabaseException(NO_SUCH_FACTORY); + } + + ArtifactCollection c = backend.getCollection( + collectionId, acf, uf, context); + + if (c == null) { + logger.warn("No collection found with identifier: " + collectionId); + throw new ArtifactDatabaseException(NO_SUCH_COLLECTION); + } + + Element root = ec.create("artifact-collection"); + ec.addAttr(root, "name", c.getName(), true); + ec.addAttr(root, "uuid", c.identifier(), true); + ec.addAttr(root, "ttl", String.valueOf(c.getTTL()), true); + + Date creationTime = c.getCreationTime(); + String creation = creationTime != null + ? Long.toString(creationTime.getTime()) + : ""; + + ec.addAttr(root, "creation", creation, true); + result.appendChild(root); + + if (masterUUID == null || masterUUID.length() == 0) { + logger.debug("No master for the collection existing."); + return result; + } + + Element master = ec.create("artifact"); + ec.addAttr(master, "uuid", masterUUID, true); + + root.appendChild(master); + + return result; + } + public Document listCollections(String userId, CallMeta callMeta) throws ArtifactDatabaseException { @@ -1769,12 +1924,6 @@ throw new ArtifactDatabaseException(NO_SUCH_COLLECTION); } - CollectionCallContext cc = new CollectionCallContext( - ArtifactDatabaseImpl.this, - CallContext.NOTHING, - callMeta, - c); - return new DeferredCollectionOutputImpl(c, type, format, callMeta); } @@ -1793,7 +1942,7 @@ } @Override - public void loadAllArtifacts(ArtifactLoadedCallback callback) + public void loadAllArtifacts(ArtifactLoadedCallback callback) throws ArtifactDatabaseException { logger.debug("loadAllArtifacts"); diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/Backend.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/Backend.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/Backend.java Fri Sep 28 12:15:12 2012 +0200 @@ -96,6 +96,7 @@ public String SQL_USERS_INSERT; public String SQL_USERS_SELECT_ID_BY_GID; public String SQL_USERS_SELECT_GID; + public String SQL_USERS_SELECT_ACCOUNT; public String SQL_USERS_DELETE_ID; public String SQL_USERS_DELETE_COLLECTIONS; public String SQL_USERS_SELECT_ALL; @@ -115,6 +116,7 @@ public String SQL_COLLECTIONS_SELECT_GID; public String SQL_COLLECTIONS_CREATION_TIME; public String SQL_COLLECTIONS_ID_BY_GID; + public String SQL_COLLECTIONS_OLDEST_ARTIFACT; public String SQL_DELETE_COLLECTION_ITEMS; public String SQL_DELETE_COLLECTION; public String SQL_COLLECTION_CHECK_ARTIFACT; @@ -310,6 +312,7 @@ SQL_USERS_INSERT = sql.get("users.insert"); SQL_USERS_SELECT_ID_BY_GID = sql.get("users.select.id.by.gid"); SQL_USERS_SELECT_GID = sql.get("users.select.gid"); + SQL_USERS_SELECT_ACCOUNT = sql.get("users.select.account"); SQL_USERS_DELETE_ID = sql.get("users.delete.id"); SQL_USERS_DELETE_COLLECTIONS = sql.get("users.delete.collections"); SQL_USERS_SELECT_ALL = sql.get("users.select.all"); @@ -332,6 +335,7 @@ SQL_COLLECTIONS_SELECT_ALL = sql.get("collections.select.all"); SQL_COLLECTIONS_SELECT_GID = sql.get("collections.select.by.gid"); SQL_COLLECTIONS_CREATION_TIME = sql.get("collection.creation.time"); + SQL_COLLECTIONS_OLDEST_ARTIFACT = sql.get("collections.artifacts.oldest"); SQL_COLLECTIONS_ID_BY_GID = sql.get("collections.id.by.gid"); SQL_DELETE_COLLECTION_ITEMS = sql.get("delete.collection.items"); SQL_DELETE_COLLECTION = sql.get("delete.collection"); @@ -807,6 +811,7 @@ public User createUser( final String name, + final String account, final Document role, final UserFactory factory, final Object context @@ -836,19 +841,20 @@ stmnt.setInt(1, id); stmnt.setString(2, identifier); stmnt.setString(3, name); + stmnt.setString(4, account); if (roleData == null) { - stmnt.setNull(4, Types.BIGINT); + stmnt.setNull(5, Types.BIGINT); } else { - stmnt.setBytes(4, roleData); + stmnt.setBytes(5, roleData); } stmnt.execute(); conn.commit(); user[0] = factory.createUser( - identifier, name, role, context); + identifier, name, account, role, context); return true; } }; @@ -963,12 +969,50 @@ } // omit id String name = result.getString(2); - byte [] roleData = result.getBytes(3); + String account = result.getString(3); + byte [] roleData = result.getBytes(4); Document role = XMLUtils.fromByteArray(roleData, true); user[0] = factory.createUser( - identifier, name, role, context); + identifier, name, account, role, context); + return true; + } + }; + + return exec.runRead() ? user[0] : null; + } + + /** + * Find/Get user by account + */ + public User findUser( + final String account, + final UserFactory factory, + final Object context + ) { + + final User [] user = new User[1]; + logger.debug("Tying to find user by account " + account); + + SQLExecutor.Instance exec = sqlExecutor.new Instance() { + public boolean doIt() throws SQLException { + prepareStatement(SQL_USERS_SELECT_ACCOUNT); + stmnt.setString(1, account); + result = stmnt.executeQuery(); + if (!result.next()) { // no such user + logger.debug("No user found."); + return false; + } + String identifier = result.getString(1); + String name = result.getString(2); + String account = result.getString(3); + byte [] roleData = result.getBytes(4); + + Document role = XMLUtils.fromByteArray(roleData, true); + + user[0] = factory.createUser( + identifier, name, account, role, context); return true; } }; @@ -991,11 +1035,12 @@ // omit id String identifier = result.getString(2); String name = result.getString(3); - byte [] roleData = result.getBytes(4); + String account = result.getString(4); + byte [] roleData = result.getBytes(5); Document role = XMLUtils.fromByteArray(roleData, true); User user = factory.createUser( - identifier, name, role, context); + identifier, name, account, role, context); users.add(user); } return true; @@ -1258,6 +1303,35 @@ } + public String getMasterArtifact(final String collectionId) { + if (!isValidIdentifier(collectionId)) { + logger.debug("Invalid collection id: '" + collectionId + "'"); + return null; + } + final String [] uuid = new String[1]; + + SQLExecutor.Instance exec = sqlExecutor.new Instance() { + public boolean doIt() throws SQLException { + // Fetch masters (oldest artifact) id. + prepareStatement(SQL_COLLECTIONS_OLDEST_ARTIFACT); + stmnt.setString(1, collectionId); + stmnt.setMaxRows(1); // + result = stmnt.executeQuery(); + if (!result.next()) { + logger.debug("No such collection: " + collectionId); + return false; + } + uuid[0] = result.getString(1); + if (logger.isDebugEnabled()) { + logger.debug("getMasterArtifact result.getString " + + uuid[0]); + } + return true; + } + }; + return exec.runRead() ? uuid[0] : null; + } + public boolean deleteCollection(final String collectionId) { if (!isValidIdentifier(collectionId)) { logger.debug("Invalid collection id: '" + collectionId + "'"); @@ -1277,6 +1351,8 @@ reset(); // outdate artifacts that are only in this collection + logger.info("Outdate Artifacts that belong to collection: " + id); + prepareStatement(SQL_OUTDATE_ARTIFACTS_COLLECTION); stmnt.setInt(1, id); stmnt.setInt(2, id); diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/DBConfig.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/DBConfig.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/DBConfig.java Fri Sep 28 12:15:12 2012 +0200 @@ -57,7 +57,7 @@ } private static DBConfig createInstance() { - + String driver = Config.getStringXPath( DB_DRIVER, DBConnection.DEFAULT_DRIVER); diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/DatabaseCleaner.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/DatabaseCleaner.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/DatabaseCleaner.java Fri Sep 28 12:15:12 2012 +0200 @@ -171,7 +171,6 @@ * Living artifacts are artifacts which are currently active * inside the artifact database. Deleting them in this state * would create severe internal problems. - * @param filter */ public void setLockedIdsProvider(LockedIdsProvider lockedIdsProvider) { this.lockedIdsProvider = lockedIdsProvider; @@ -219,7 +218,7 @@ } } // class IdIdentifier - private static final class IdData + private static final class IdData extends IdIdentifier { byte [] data; @@ -227,7 +226,7 @@ public IdData( int id, - String factoryName, + String factoryName, byte [] data, String identifier ) { @@ -307,6 +306,7 @@ stmnt = connection.prepareStatement(SQL_DELETE_COLLECTION_ITEMS); for (IdIdentifier id: cs) { + logger.debug("Mark collection for deletion: " + id.id); stmnt.setInt(1, id.id); stmnt.execute(); } @@ -355,17 +355,23 @@ idData.factoryName, idData.data); idData.data = null; + logger.debug("Prepare Artifact (id=" + + idData.id + ") for deletion."); + stmnt.setInt(1, idData.id); stmnt.execute(); connection.commit(); try { if (artifact != null) { + logger.debug("Call endOfLife for Artifact: " + + artifact.identifier()); + artifact.endOfLife(context); } } catch (Exception e) { - logger.error(e.getLocalizedMessage(), e); + logger.error(e.getMessage(), e); } deletedArtifacts.add(idData.identifier); diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifact.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifact.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifact.java Fri Sep 28 12:15:12 2012 +0200 @@ -36,6 +36,7 @@ */ protected String identifier; + /** * Default constructor. */ @@ -58,6 +59,7 @@ return this.identifier; } + public String hash() { String hash = String.valueOf(hashCode()); if (logger.isDebugEnabled()) { @@ -113,8 +115,12 @@ } } - public void setup(String identifier, ArtifactFactory factory, - Object context, CallMeta callMeta, Document data) { + public void setup(String identifier, + ArtifactFactory factory, + Object context, + CallMeta callMeta, + Document data) + { if (logger.isDebugEnabled()) { logger.debug("DefaultArtifact.setup: " + identifier); } diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactCollection.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactCollection.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactCollection.java Fri Sep 28 12:15:12 2012 +0200 @@ -36,33 +36,23 @@ public class DefaultArtifactCollection implements ArtifactCollection { - /** The logger used in this class.*/ + /** The logger used in this class. */ private static Logger logger = Logger.getLogger(DefaultArtifactCollection.class); - /** - * The identifier of the collection. - */ + /** The identifier of the collection. */ protected String identifier; - /** - * The identifier of the collection. - */ + /** The identifier of the collection. */ protected String name; - /** - * The owner of this collection. - */ + /** The owner of this collection. */ protected User user; - /** - * The attribute of this collection. - */ + /** The attribute of this collection. */ protected Document attribute; - /** - * The artifacts stored in this collection. - */ + /** The artifacts stored in this collection. */ protected List artifacts; /** @@ -151,7 +141,7 @@ /** * Name of this collection. - * @return Returns the name of this collection + * @param name the name of this collection */ public void setName(String name) { this.name = name; diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactCollectionFactory.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactCollectionFactory.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactCollectionFactory.java Fri Sep 28 12:15:12 2012 +0200 @@ -103,8 +103,6 @@ /** * Returns the time to live of the given artifact. - * - * @param artifact */ public Long timeToLiveUntouched( ArtifactCollection collection, @@ -134,7 +132,13 @@ ArtifactCollection collection = (ArtifactCollection) clazz.newInstance(); - collection.setup(identifier, name, creationTime, ttl, this, context, data); + collection.setup(identifier, + name, + creationTime, + ttl, + this, + context, + data); return collection; } diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactContext.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactContext.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultArtifactContext.java Fri Sep 28 12:15:12 2012 +0200 @@ -30,7 +30,7 @@ /** * Custom key/value pairs to be used globally in the whole server. */ - protected HashMap map; + protected HashMap map; /** * Default constructor diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultService.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultService.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultService.java Fri Sep 28 12:15:12 2012 +0200 @@ -8,8 +8,6 @@ package de.intevation.artifactdatabase; -import de.intevation.artifacts.common.utils.XMLUtils; - import de.intevation.artifacts.CallMeta; import de.intevation.artifacts.Service; import de.intevation.artifacts.GlobalContext; @@ -30,14 +28,38 @@ { private static Logger logger = Logger.getLogger(DefaultService.class); + public static class Output implements Service.Output { + + protected Object data; + protected String mimeType; + + public Output() { + } + + public Output(Object data, String mimeType) { + this.data = data; + this.mimeType = mimeType; + } + + @Override + public Object getData() { + return data; + } + + @Override + public String getMIMEType() { + return mimeType; + } + } // class Output + @Override - public Document process( + public Service.Output process( Document data, GlobalContext globalContext, CallMeta callMeta ) { logger.debug("Service.process"); - return XMLUtils.newDocument(); + return new Output(new byte[0], "application/octet-stream"); } @Override diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultUser.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultUser.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultUser.java Fri Sep 28 12:15:12 2012 +0200 @@ -25,6 +25,9 @@ /** The name of the user.*/ protected String name; + /** The account name of the user.*/ + protected String account; + /** The role of the user.*/ protected Document role; @@ -44,12 +47,15 @@ * * @param identifier The uuid of the user. * @param name The name of the user. + * @param account The account name of the user. * @param role The role of the user. */ - public DefaultUser(String identifier, String name, Document role) { + public DefaultUser(String identifier, String name, String account, + Document role) { this.identifier = identifier; this.name = name; this.role = role; + this.account = account; } @@ -58,6 +64,7 @@ * * @return the identifier of this user. */ + @Override public String identifier() { return identifier; } @@ -68,6 +75,7 @@ * * @return the name of the user. */ + @Override public String getName() { return name; } @@ -78,6 +86,7 @@ * * @param name The name for this user. */ + @Override public void setName(String name) { this.name = name; } @@ -88,6 +97,7 @@ * * @param identifier The new identifier. */ + @Override public void setIdentifier(String identifier) { this.identifier = identifier; } @@ -98,6 +108,7 @@ * * @param role The new role of the user. */ + @Override public void setRole(Document role) { this.role = role; } @@ -108,8 +119,19 @@ * * @return the role of the user. */ + @Override public Document getRole() { return role; } + + /** + * Returns the account of the user. + * + * @return the account name of the user. + */ + @Override + public String getAccount() { + return account; + } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultUserFactory.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultUserFactory.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/DefaultUserFactory.java Fri Sep 28 12:15:12 2012 +0200 @@ -47,17 +47,19 @@ * * @param identifier The identifier for the new user. * @param name The name for the new user. + * @param account The name of the new users account. * @param role The role for the new user. * @param context The CallContext. */ public User createUser( String identifier, String name, + String account, Document role, Object context) { logger.debug("DefaultUserFactory.createUser: " + name); - return new DefaultUser(identifier, name, role); + return new DefaultUser(identifier, name, account, role); } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/FactoryBootstrap.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/FactoryBootstrap.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/FactoryBootstrap.java Fri Sep 28 12:15:12 2012 +0200 @@ -170,6 +170,8 @@ protected List postAdvanceHooks; + protected List postDescribeHooks; + protected List lifetimeListeners; protected List backendListeners; @@ -542,8 +544,9 @@ protected void loadHooks() { logger.info("loading hooks"); - postFeedHooks = new ArrayList(); - postAdvanceHooks = new ArrayList(); + postFeedHooks = new ArrayList(); + postAdvanceHooks = new ArrayList(); + postDescribeHooks = new ArrayList(); NodeList nodes = Config.getNodeSetXPath(HOOKS); @@ -567,6 +570,9 @@ else if (a.equals("post-advance")) { postAdvanceHooks.add(hook); } + else if (a.equals("post-describe")) { + postDescribeHooks.add(hook); + } } } } @@ -703,6 +709,10 @@ return postAdvanceHooks; } + public List getPostDescribeHooks() { + return postDescribeHooks; + } + public HTTPServer getHTTPServer() { return httpServer; } diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/LazyBackendUser.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/LazyBackendUser.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/LazyBackendUser.java Fri Sep 28 12:15:12 2012 +0200 @@ -43,28 +43,39 @@ return user; } + @Override public String identifier() { return getUser().identifier(); } + @Override public String getName() { return getUser().getName(); } + @Override public void setName(String name) { getUser().setName(name); } + @Override public void setIdentifier(String identifier) { getUser().setIdentifier(identifier); } + @Override public Document getRole() { return getUser().getRole(); } + @Override public void setRole(Document document) { getUser().setRole(document); } + + @Override + public String getAccount() { + return getUser().getAccount(); + } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/ProtocolUtils.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/ProtocolUtils.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/ProtocolUtils.java Fri Sep 28 12:15:12 2012 +0200 @@ -157,7 +157,7 @@ * This method appends a node for each Output in the outputs list to * out. Note: an output node includes its provided facets! * - * @param creator The ElementCreator used to create new elements. + * @param doc The document to which to add new elements. * @param out The parent node for new elements. * @param outputs The list of reachable outputs. */ @@ -195,7 +195,7 @@ * This method appends a node for each Facet in the facets list to * facet. * - * @param creator The ElementCreator used to create new elements. + * @param doc The document to wich to add new elements. * @param facet The root node for new elements. * @param facets The list of facets. */ diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/XMLService.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/XMLService.java Fri Sep 28 12:15:12 2012 +0200 @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2010 by Intevation GmbH + * + * This program is free software under the LGPL (>=v2.1) + * Read the file LGPL.txt coming with the software for details + * or visit http://www.gnu.org/licenses/ if it does not exist. + */ + +package de.intevation.artifactdatabase; + +import de.intevation.artifacts.CallMeta; +import de.intevation.artifacts.Service; +import de.intevation.artifacts.GlobalContext; + +import de.intevation.artifacts.common.utils.XMLUtils; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Document; + +/** + * Trivial implementation of an artifact database service. Useful to + * be subclassed. + * + * @author Sascha L. Teichmann + */ +public class XMLService +extends DefaultService +{ + private static Logger logger = Logger.getLogger(XMLService.class); + + @Override + public Service.Output process( + Document data, + GlobalContext globalContext, + CallMeta callMeta + ) { + return new Output( + processXML(data, globalContext, callMeta), + "application/xml"); + } + + public Document processXML( + Document data, + GlobalContext globalContext, + CallMeta callMeta + ) { + return XMLUtils.newDocument(); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/db/DBConnection.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/db/DBConnection.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/db/DBConnection.java Fri Sep 28 12:15:12 2012 +0200 @@ -96,7 +96,9 @@ } try { - Class.forName(driver); + synchronized (DBConnection.class) { + Class.forName(driver); + } } catch (ClassNotFoundException cnfe) { log.error("cannot load driver", cnfe); diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/db/SQL.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/db/SQL.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/db/SQL.java Fri Sep 28 12:15:12 2012 +0200 @@ -50,7 +50,7 @@ Class clazz, String resourcePath, String driver - ) { + ) { logger.debug("loadStatements"); Properties properties = new Properties(); @@ -105,7 +105,7 @@ } if (debug) { - logger.debug("-> '" + sql + "'"); + logger.debug("-> '" + sql + "'"); } return sql; diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/ByteArrayRepresentation.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/ByteArrayRepresentation.java Fri Sep 28 12:15:12 2012 +0200 @@ -0,0 +1,65 @@ +package de.intevation.artifactdatabase.rest; + +import org.restlet.representation.Representation; + +import java.io.Reader; +import java.io.OutputStream; +import java.io.InputStream; +import java.io.Writer; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.ByteArrayInputStream; + +import java.nio.ByteBuffer; + +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.WritableByteChannel; + +import org.restlet.data.MediaType; + +public class ByteArrayRepresentation +extends Representation +{ + protected byte [] data; + + public ByteArrayRepresentation(MediaType mediaType, byte [] data) { + super(mediaType); + this.data = data; + } + + @Override + public long getSize() { + return data.length; + } + + @Override + public ReadableByteChannel getChannel() throws IOException { + return null; + } + + @Override + public Reader getReader() throws IOException { + return new InputStreamReader(getStream()); + } + + @Override + public InputStream getStream() throws IOException { + return new ByteArrayInputStream(data); + } + + @Override + public void write(Writer writer) throws IOException { + writer.append(ByteBuffer.wrap(data).asCharBuffer()); + } + + @Override + public void write(WritableByteChannel writableChannel) throws IOException { + writableChannel.write(ByteBuffer.wrap(data)); + } + + @Override + public void write(OutputStream outputStream) throws IOException { + outputStream.write(data); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/FindUserResource.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/FindUserResource.java Fri Sep 28 12:15:12 2012 +0200 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2011 by Intevation GmbH + * + * This program is free software under the LGPL (>=v2.1) + * Read the file LGPL.txt coming with the software for details + * or visit http://www.gnu.org/licenses/ if it does not exist. + */ +package de.intevation.artifactdatabase.rest; + +import java.io.IOException; + +import org.apache.log4j.Logger; + +import org.restlet.data.MediaType; +import org.restlet.data.Status; +import org.restlet.ext.xml.DomRepresentation; +import org.restlet.representation.EmptyRepresentation; +import org.restlet.representation.Representation; +import org.restlet.resource.ResourceException; +import org.restlet.Response; + +import org.w3c.dom.Document; + +import de.intevation.artifacts.ArtifactDatabase; +import de.intevation.artifacts.ArtifactDatabaseException; + +/** + * A Rest resource that finds the user provided by the artifact database. + * + */ +public class FindUserResource +extends BaseResource +{ + /** The logger that is used in this class.*/ + private static Logger logger = Logger.getLogger(FindUserResource.class); + + /** server URL where to reach the resource.*/ + public static final String PATH = "/find-user"; + + + @Override + protected Representation innerPost(Representation requestRepr) + throws ResourceException + { + Document input = null; + + try { + DomRepresentation in = new DomRepresentation(requestRepr); + in.setNamespaceAware(true); + input = in.getDocument(); + } + catch (IOException ioe) { + logger.error(ioe.getLocalizedMessage(), ioe); + + Response response = getResponse(); + response.setStatus(Status.CLIENT_ERROR_BAD_REQUEST, ioe); + return new EmptyRepresentation(); + } + + ArtifactDatabase db = getArtifactDatabase(); + + try { + logger.info(PATH); + + return new DomRepresentation( + MediaType.APPLICATION_XML, + db.findUser(input, getCallMeta())); + } + catch (ArtifactDatabaseException adbe) { + logger.warn(adbe.getLocalizedMessage(), adbe); + + Response response = getResponse(); + response.setStatus( + Status.CLIENT_ERROR_UNPROCESSABLE_ENTITY, adbe.getMessage()); + return new EmptyRepresentation(); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/RestApp.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/RestApp.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/RestApp.java Fri Sep 28 12:15:12 2012 +0200 @@ -81,6 +81,7 @@ 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( diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/ServiceResource.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/ServiceResource.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/ServiceResource.java Fri Sep 28 12:15:12 2012 +0200 @@ -27,6 +27,8 @@ import org.w3c.dom.Document; +import de.intevation.artifacts.Service; + /** * Resource to process incoming XML documents with a given service. * @@ -72,8 +74,7 @@ .getAttributes().get("database"); try { - return new DomRepresentation( - MediaType.APPLICATION_XML, + return guessRepresentation( db.process(service, inputDocument, getCallMeta())); } catch (ArtifactDatabaseException adbe) { @@ -84,5 +85,21 @@ return new EmptyRepresentation(); } } + + protected static Representation guessRepresentation(Service.Output output) { + + MediaType mediaType = new MediaType(output.getMIMEType()); + Object data = output.getData(); + + if (data instanceof Document) { + return new DomRepresentation(mediaType, (Document)data); + } + + if (data instanceof byte []) { + return new ByteArrayRepresentation(mediaType, (byte [])data); + } + + return new EmptyRepresentation(); + } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/rest/UserResource.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/UserResource.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/rest/UserResource.java Fri Sep 28 12:15:12 2012 +0200 @@ -35,10 +35,10 @@ public class UserResource extends BaseResource { - /** The logger that is used in this class.*/ + /** The logger that is used in this class. */ private static Logger logger = Logger.getLogger(UserResource.class); - /** server URL where to reach the resource.*/ + /** server URL where to reach the resource. */ public static final String PATH = "/user/{uuid}"; /** @@ -47,13 +47,13 @@ */ public static final String XPATH_ACTION = "/art:action/art:type/@name"; - /** Error message if no action was given.*/ + /** Error message if no action was given. */ public static final String NO_ACTION_MSG = "no action given"; - /** Error message if a unknown action was given.*/ + /** Error message if a unknown action was given. */ public static final String NO_SUCH_ACTION_MSG = "no such action"; - /** Action name for deleting users.*/ + /** Action name for deleting users. */ public static final String ACTION_DELETE = "delete"; diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/state/AbstractState.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/state/AbstractState.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/state/AbstractState.java Fri Sep 28 12:15:12 2012 +0200 @@ -24,6 +24,7 @@ import de.intevation.artifacts.Artifact; import de.intevation.artifacts.ArtifactNamespaceContext; import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; import de.intevation.artifacts.common.utils.XMLUtils; @@ -46,15 +47,18 @@ * the configuration. */ public static final String XPATH_DESCRIPTION = "@description"; - /** The XPath to the output nodes of the state configuration.*/ + /** The XPath that points to the help text.*/ + public static final String XPATH_HELP_TEXT = "@helpText"; + + /** The XPath to the output nodes of the state configuration. */ public static final String XPATH_OUTPUT_MODES = "outputmodes/outputmode"; /** The XPath to the list of facets relative to the output mode it belongs - * to.*/ + * to. */ public static final String XPATH_FACETS = "facets/facet"; - /** The logger that is used in this class.*/ + /** The logger that is used in this class. */ private static Logger logger = Logger.getLogger(AbstractState.class); @@ -64,10 +68,13 @@ /** The description of the state. */ protected String description; + /** The help text for this state.*/ + protected String helpText; + /** The data provided by this state. */ protected Map data; - /** A list of output modes which are available for this state.*/ + /** A list of output modes which are available for this state. */ protected List outputs; @@ -87,7 +94,12 @@ this.id = id; this.description = description; + } + + public AbstractState(String id, String description, String helpText) { + this(id, description); + this.helpText = helpText; } @@ -132,6 +144,26 @@ /** + * Returns the help text of this state. + * + * @return the help text. + */ + public String getHelpText() { + return helpText; + } + + + /** + * Set the help text for this state. + * + * @param helpText The help text. + */ + public void setHelpText(String helpText) { + this.helpText = helpText; + } + + + /** * Returns the data of the state. * * @return the data of the state. @@ -149,7 +181,11 @@ * @return a data object of the state or null if no such data object exists. */ public StateData getData(String name) { - return data.get(name); + if (data != null) { + return data.get(name); + } + + return null; } @@ -158,7 +194,7 @@ * with the key name, this object is overwritten by the new value. * * @param name The name of the data object. - * @param StateData The data object. + * @param data The data object. */ public void addData(String name, StateData data) { if (this.data == null) { @@ -193,11 +229,32 @@ description = (String) XMLUtils.xpath( config, XPATH_DESCRIPTION, XPathConstants.STRING); + helpText = (String) XMLUtils.xpath( + config, XPATH_HELP_TEXT, XPathConstants.STRING); + setupOutputs(config); } /** + * This default implementation does nothing at all. + * + * @param orig + * @param owner + * @param context + * @param callMeta + */ + public void initialize( + Artifact orig, + Artifact owner, + Object context, + CallMeta callMeta + ) { + // do nothing. + } + + + /** * This method tries reading the available output nodes configured in the * state configuration and adds possible Outputs to the outputs list. * @@ -217,10 +274,18 @@ int size = outs.getLength(); for (int i = 0; i < size; i++) { - outputs.add(buildOutput(outs.item(i))); + addOutput(buildOutput(outs.item(i))); } } + /** + * This methods allows subclasses to manually add outputs + * + * @param out The output to add + */ + protected void addOutput(Output out) { + outputs.add(out); + } /** * A helper method that creates an Output object based on the out diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/state/ArtifactAndFacet.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/state/ArtifactAndFacet.java Fri Sep 28 12:15:12 2012 +0200 @@ -0,0 +1,97 @@ +package de.intevation.artifactdatabase.state; + +import java.util.List; + +import de.intevation.artifacts.Artifact; +import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.DataProvider; + + +/** + * A bundle of a "native" Facet and its Artifact. + */ +public class ArtifactAndFacet implements DataProvider { + /** The Artifact. */ + protected Artifact artifact; + + /** The (native) facet. */ + protected Facet facet; + + /** An alternative facet description that might be set from outside. */ + protected String facetDescription; + + + /** Trivial constructor. */ + public ArtifactAndFacet( + Artifact a, + Facet f + ) { + this.artifact = a; + this.facet = f; + } + + + /** Get data (to plot). */ + public Object getData(CallContext context) { + return facet.getData(artifact, context); + } + + + /** Get data (for other facet). */ + @Override + public Object provideData(Object key, Object param, CallContext context) { + return facet.provideBlackboardData(artifact, key, param, context); + } + + + /** (Maybe) Register on blackboard (depending on facet). */ + @Override + public void register(CallContext context) { + List keys = facet.getDataProviderKeys(this.artifact, context); + if (keys == null) { + return; + } + for (Object key: keys) { + context.registerDataProvider(key, this); + } + } + + + /** Access the artifact. */ + public Artifact getArtifact() { + return artifact; + } + + + /** Access the (native) facet. */ + public Facet getFacet() { + return facet; + } + + + /** Shortcut to facets name. */ + public String getFacetName() { + return facet.getName(); + } + + + /** + * Returns the description for a facet. The return value depends on the + * internal facetDescription instance variable. If this has been set + * by setFacetDescription, this value is returned, otherwise the return + * value of facet.getDescription(). + */ + public String getFacetDescription() { + if (facetDescription == null) { + return facet.getDescription(); + } + + return facetDescription; + } + + + public void setFacetDescription(String facetDescription) { + this.facetDescription = facetDescription; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/state/Attribute.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/state/Attribute.java Fri Sep 28 12:15:12 2012 +0200 @@ -0,0 +1,43 @@ +package de.intevation.artifactdatabase.state; + +import java.io.Serializable; + +import org.w3c.dom.Node; + + +/** + * @author Ingo Weinzierl + */ +public interface Attribute extends Serializable { + + /** + * Returns the name of this Attribute. + * + * @return the name of this Attribute. + */ + String getName(); + + /** + * Returns the value of this Attribute. + * + * @return the value of this Attribute. + */ + Object getValue(); + + /** + * Sets the value of this Attribute. + * + * @param value The new value. + */ + void setValue(Object value); + + /** + * Transforms this Attribute into XML. + * + * @param parent The parent node. + * + * @return the Node that represents this Attribute. + */ + Node toXML(Node parent); +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultAttribute.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultAttribute.java Fri Sep 28 12:15:12 2012 +0200 @@ -0,0 +1,54 @@ +package de.intevation.artifactdatabase.state; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + + +/** + * @author Ingo Weinzierl + */ +public class DefaultAttribute implements Attribute { + + protected String name; + + protected Object value; + + + public DefaultAttribute(String name, Object value) { + this.name = name; + this.value = value; + } + + + @Override + public String getName() { + return name; + } + + + @Override + public Object getValue() { + return value; + } + + + @Override + public void setValue(Object value) { + this.value = value; + } + + + @Override + public Node toXML(Node parent) { + Document owner = parent.getOwnerDocument(); + Element attr = owner.createElement(getName()); + + parent.appendChild(attr); + + attr.setTextContent(String.valueOf(getValue())); + + return attr; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultFacet.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultFacet.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultFacet.java Fri Sep 28 12:15:12 2012 +0200 @@ -1,5 +1,7 @@ package de.intevation.artifactdatabase.state; +import java.util.List; + import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; @@ -18,18 +20,21 @@ */ public class DefaultFacet implements Facet { - /** The index of this facet.*/ + /** The index of this facet. */ protected int index; - /** The name of this facet.*/ + /** The name of this facet. */ protected String name; - /** The description of this facet.*/ + /** The description of this facet. */ protected String description; + + /** Trivial, empty constructor. */ public DefaultFacet() { } + /** * The default constructor to create new Facet objects. * @@ -54,47 +59,70 @@ this.description = description; } - public void set(Facet other) { - index = other.getIndex(); - name = other.getName(); - description = other.getDescription(); - } - public Facet deepCopy() { - DefaultFacet copy = new DefaultFacet(); - copy.set(this); - return copy; - } - - + /** Get index. */ public int getIndex() { return index; } + /** Returns the name ('type'). */ public String getName() { return name; } + /** Returns the description (e.g. displayed in gui). */ public String getDescription() { return description; } + /** + * @return null + */ public Object getData(Artifact artifact, CallContext context) { return null; } - public String toString() { - return new StringBuilder("name = '") - .append(name).append("', index = ") - .append(index).append(", description = '") - .append(description).append("'") - .toString(); + + /** + * (Do not) provide data. + * Override to allow other facets to access your data. + * @return always null. + */ + public Object provideBlackboardData( + Artifact artifact, + Object key, + Object param, + CallContext context + ) { + return null; } + /* + * Return list of keys (objects) for which this facet can provide data + * ("external parameterization"), for other facets, via blackboard. + * These are the keys that are independent from the current call (thus + * 'static'). + * @param artifact that this facet belongs to. + */ + public List getStaticDataProviderKeys(Artifact artifact) { + return null; + } + + /** + * Return list of keys (objects) for which this facet can provide data + * ("external parameterization"), for other facets, via blackboard. + * @param artifact that this facet belongs to. + */ + public List getDataProviderKeys(Artifact artifact, CallContext context) { + return getStaticDataProviderKeys(artifact); + } + + + /** Create a xml represantation. */ public Node toXML(Document doc) { ElementCreator ec = new ElementCreator( doc, @@ -108,5 +136,33 @@ return facet; } + + + /** Create a string representation. */ + public String toString() { + return new StringBuilder("name = '") + .append(name).append("', index = ") + .append(index).append(", description = '") + .append(description).append("'") + .toString(); + } + + + /** + * Copies name, index and description of other facet. + */ + public void set(Facet other) { + index = other.getIndex(); + name = other.getName(); + description = other.getDescription(); + } + + + /** Create a deep copy of this facet. */ + public Facet deepCopy() { + DefaultFacet copy = new DefaultFacet(); + copy.set(this); + return copy; + } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultOutput.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultOutput.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultOutput.java Fri Sep 28 12:15:12 2012 +0200 @@ -20,6 +20,8 @@ protected List facets; + protected Settings settings; + /** * The default constructor that instantiates a new DefaultOutput object. @@ -130,12 +132,32 @@ public void addFacet(Facet facet) { - facets.add(facet); + if (facet != null && !facets.contains(facet)) { + facets.add(facet); + } } public void addFacets(List facets) { this.facets.addAll(facets); } + + + @Override + public void setFacets(List facets) { + this.facets = facets; + } + + + @Override + public void setSettings(Settings settings) { + this.settings = settings; + } + + + @Override + public Settings getSettings() { + return settings; + } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultSection.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultSection.java Fri Sep 28 12:15:12 2012 +0200 @@ -0,0 +1,112 @@ +package de.intevation.artifactdatabase.state; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + +/** + * Attributes keep the order in which they were inserted. + * @author Ingo Weinzierl + */ +public class DefaultSection implements Section { + + protected String id; + + protected List
subsections; + + /** Attribute-map. */ + protected Map attributes; + + + /** + * Creates a new DefaultSection instance. Note, that the id is used + * as Node name of the new Element that is created in toXML(). + */ + public DefaultSection(String id) { + this.id = id; + // Use LinkedHashMap to keep insertion order. + this.attributes = new LinkedHashMap(); + this.subsections = new ArrayList
(); + } + + + @Override + public String getId() { + return id; + } + + + @Override + public void addSubsection(Section subsection) { + if (subsection != null) { + subsections.add(subsection); + } + } + + + @Override + public int getSubsectionCount() { + return subsections.size(); + } + + + @Override + public Section getSubsection(int pos) { + if (pos >= 0 && pos < getSubsectionCount()) { + return subsections.get(pos); + } + + return null; + } + + + /** Adding attribute to end of list. */ + @Override + public void addAttribute(String key, Attribute attribute) { + if (key != null && key.length() > 0 && attribute != null) { + attributes.put(key, attribute); + } + } + + + @Override + public Attribute getAttribute(String key) { + if (key == null || key.length() == 0) { + return null; + } + + return attributes.get(key); + } + + + @Override + public Set getKeys() { + return attributes.keySet(); + } + + + @Override + public void toXML(Node parent) { + Document owner = parent.getOwnerDocument(); + Element sectionEl = owner.createElement(getId()); + + parent.appendChild(sectionEl); + + for (String key: getKeys()) { + Attribute attr = getAttribute(key); + attr.toXML(sectionEl); + } + + for (int i = 0, n = getSubsectionCount(); i < n; i++) { + Section subsection = getSubsection(i); + subsection.toXML(sectionEl); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultSettings.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/state/DefaultSettings.java Fri Sep 28 12:15:12 2012 +0200 @@ -0,0 +1,62 @@ +package de.intevation.artifactdatabase.state; + +import java.util.ArrayList; +import java.util.List; + +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.Node; + + +/** + * @author Ingo Weinzierl + */ +public class DefaultSettings implements Settings { + + protected List
sections; + + public DefaultSettings() { + sections = new ArrayList
(); + } + + @Override + public void addSection(Section section) { + if (section != null) { + sections.add(section); + } + } + + @Override + public int getSectionCount() { + return sections.size(); + } + + @Override + public Section getSection(int pos) { + if (pos >= 0 && pos < getSectionCount()) { + return sections.get(pos); + } + + return null; + } + + @Override + public void removeSection(Section section) { + if (section != null) { + sections.remove(section); + } + } + + @Override + public void toXML(Node parent) { + Document owner = parent.getOwnerDocument(); + Element settings = owner.createElement("settings"); + + parent.appendChild(settings); + + for (Section section: sections) { + section.toXML(settings); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/state/Facet.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/state/Facet.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/state/Facet.java Fri Sep 28 12:15:12 2012 +0200 @@ -1,5 +1,7 @@ package de.intevation.artifactdatabase.state; +import java.util.List; + import java.io.Serializable; import org.w3c.dom.Document; @@ -49,6 +51,32 @@ /** + * Get keys for which this Facet can provide data (for other facets, not + * for plot). + * @param artifact Artifact that this facet belongs to. + * @return list of keys + */ + List getDataProviderKeys(Artifact artifact, CallContext context); + + + /** + * Provide data to other facet. + * + * @param art The artifact that this facet belongs to. + * @param key the key of the requested service. + * @param prm optional parameters. + * @param ctxt the callcontext. + * + * @return the data + */ + Object provideBlackboardData( + Artifact art, + Object key, + Object prm, + CallContext ctxt); + + + /** * Write the internal representation of a facet to a node. * * @param doc A Document. diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/state/FacetActivity.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/state/FacetActivity.java Fri Sep 28 12:15:12 2012 +0200 @@ -0,0 +1,80 @@ +package de.intevation.artifactdatabase.state; + +import de.intevation.artifacts.Artifact; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public interface FacetActivity +{ + public static final FacetActivity ACTIVE = new FacetActivity() { + @Override + public Boolean isInitialActive( + Artifact artifact, + Facet facet, + String output + ) { + return Boolean.TRUE; + } + }; + + public static final FacetActivity INACTIVE = new FacetActivity() { + @Override + public Boolean isInitialActive( + Artifact artifact, + Facet facet, + String output + ) { + return Boolean.FALSE; + } + }; + + Boolean isInitialActive(Artifact artifact, Facet facet, String output); + + public static final class Registry { + + private static final Registry INSTANCE = new Registry(); + + private Map> activities; + + private Registry() { + activities = new HashMap>(); + } + + public static Registry getInstance() { + return INSTANCE; + } + + public synchronized boolean isInitialActive( + String key, + Artifact artifact, + Facet facet, + String output + ) { + List activityList = activities.get(key); + if (activityList == null) { + return true; + } + for (FacetActivity activity: activityList) { + Boolean isActive = + activity.isInitialActive(artifact, facet, output); + if (isActive != null) { + return isActive; + } + } + return true; + } + + public synchronized void register(String key, FacetActivity activity) { + List activityList = activities.get(key); + if (activityList == null) { + activityList = new ArrayList(3); + activities.put(key, activityList); + } + activityList.add(activity); + } + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/state/Output.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/state/Output.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/state/Output.java Fri Sep 28 12:15:12 2012 +0200 @@ -57,5 +57,24 @@ * @param facets A list of facets. */ public void addFacets(List facets); + + /** + * Replaces the old list of facets with a new one. + * + * @param facets A list of new facets. + */ + public void setFacets(List facets); + + /** + * Returns a Settings object for this Output. + */ + public Settings getSettings(); + + /** + * Sets the Settings for this Output. + * + * @param settings the Settings for this Output. + */ + public void setSettings(Settings settings); } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/state/Section.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/state/Section.java Fri Sep 28 12:15:12 2012 +0200 @@ -0,0 +1,76 @@ +package de.intevation.artifactdatabase.state; + +import java.io.Serializable; +import java.util.Set; + +import org.w3c.dom.Node; + + +/** + * @author Ingo Weinzierl + */ +public interface Section extends Serializable { + + /** + * Returns an ID for this Section. + * + * @return an ID for this Section. + */ + String getId(); + + /** + * Adds a new subsection to this Section object. + * + * @param subsection the new Section. + */ + void addSubsection(Section subsection); + + /** + * Returns the number of subsections in this Section. + * + * @return the number of subsections. + */ + int getSubsectionCount(); + + /** + * Returns a subsection at position pos. + * + * @param pos The position of the target subsection. + * + * @return the subsection at position pos. + */ + Section getSubsection(int pos); + + /** + * Adds a new Attribute to this Section. + * + * @param key The key that is used to store/retrieve the Attribute. + * @param attribute The new Attribute. + */ + void addAttribute(String key, Attribute attribute); + + /** + * Returns an Attribute for the specified key. + * + * @param key The key that is used to retrieve the target Attribute. + * + * @return the Attribute specified by key. + */ + Attribute getAttribute(String key); + + /** + * Returns all keys of all Attributes currently stored in this Section. + * + * @return all keys of all Attributes. + */ + Set getKeys(); + + /** + * Transforms this Section into XML using Attribute.toXML() for each + * Attribute and Section.toXML() for each subsection stored in this Section. + * + * @param parent The parent node. + */ + void toXML(Node parent); +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/state/Settings.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/state/Settings.java Fri Sep 28 12:15:12 2012 +0200 @@ -0,0 +1,53 @@ +package de.intevation.artifactdatabase.state; + +import java.io.Serializable; + +import org.w3c.dom.Node; + + +/** + * @author Ingo Weinzierl + */ +public interface Settings extends Serializable { + + /** + * Adds a new Section to this Settings object. + * + * @param section the new Section. + */ + void addSection(Section section); + + /** + * Returns the number of Sections in this Settings object. + * + * @return the number of sections. + */ + int getSectionCount(); + + /** + * Returns the section at position pos. + * + * @param pos the position of the target Section. + * + * @return the Section at position pos or null if no Section is + * existing at pos. + */ + Section getSection(int pos); + + /** + * Removes a Section if it is existing in this Settings. + * + * @param section The section that should be removed. + */ + void removeSection(Section section); + + /** + * Transforms this Settings object into a XML representation. Therefore, + * each Section object's toXML method is called to append its XML + * representation to the final document. + * + * @param parent The parent node. + */ + void toXML(Node parent); +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf-8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/state/State.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/state/State.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/state/State.java Fri Sep 28 12:15:12 2012 +0200 @@ -17,6 +17,7 @@ import de.intevation.artifacts.Artifact; import de.intevation.artifacts.CallContext; +import de.intevation.artifacts.CallMeta; import de.intevation.artifactdatabase.data.StateData; @@ -46,6 +47,14 @@ /** + * Returns the help text configured for the state. + * + * @return the help text configured for the state. + */ + public String getHelpText(); + + + /** * Returns the data provided by this state. * * @return the data stored in this state. @@ -91,6 +100,21 @@ /** + * Initializes the internal state of this State based on an other State. + * + * @param orig The owner Artifact or the original State. + * @param owner The owner Artifact of this State. + * @param context The context object. + * @param callMeta The CallMeta of the current call. + */ + public void initialize( + Artifact orig, + Artifact owner, + Object context, + CallMeta callMeta); + + + /** * This method is called when an artifacts retrieves a describe request. It * creates the user interface description of the current state. * diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/state/StateEngine.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/state/StateEngine.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/state/StateEngine.java Fri Sep 28 12:15:12 2012 +0200 @@ -1,13 +1,18 @@ package de.intevation.artifactdatabase.state; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.log4j.Logger; +import de.intevation.artifactdatabase.data.StateData; + + /** - * The StateEngine stores all states for each Artifact. + * The StateEngine stores all states and associated information about + * outputs and facets for each Artifact. * * @author Ingo Weinzierl */ @@ -62,6 +67,30 @@ } + public StateData getStateData(String artifact, String dataName) { + List artifactStates = getStates(artifact); + + if (artifactStates == null || artifactStates.size() == 0) { + logger.warn("No States for Artifact '" + artifact + "' existing."); + return null; + } + + for (State state: artifactStates) { + StateData sd = state.getData(dataName); + + if (sd != null) { + return sd; + } + } + + logger.warn( + "No StateData for Artifact '" + artifact + + "' with name '" + dataName + "' existing."); + + return null; + } + + /** * Add new states for a specific artifact. * @@ -93,7 +122,7 @@ /** * Returns the state list of an artifact specified by its name. * - * @param artifact The name of the artifact. + * @param artifact The name of the artifact (e.g. "winfo"). * * @return the list of states of this artifact or null if no states * are existing for this artifact. @@ -101,5 +130,40 @@ public List getStates(String artifact) { return states.get(artifact); } + + + /** + * Return mapping of output to facets for an artifact in its states. + */ + public Map> getCompatibleFacets(List aStates) { + Map> compatibilityMatrix = + new HashMap>(); + + // For all states that the artifact had seen, add outputs facets. + for (String stateId: aStates) { + + State state = allStates.get(stateId); + if (state == null) { + continue; + } + + for (Output output: state.getOutputs()) { + List outFacets = output.getFacets(); + + List oldFacets = compatibilityMatrix.get(output.getName()); + + if (oldFacets == null) { + oldFacets = new ArrayList(); + } + + for (Facet facet: outFacets) { + oldFacets.add(facet.getName()); + } + + compatibilityMatrix.put(output.getName(), oldFacets); + } + } + return compatibilityMatrix; + } } -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : +// vim:set ts=4 sw=4 et sta sts=4 fenc=utf8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/java/de/intevation/artifactdatabase/transition/TransitionEngine.java --- a/artifact-database/src/main/java/de/intevation/artifactdatabase/transition/TransitionEngine.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/java/de/intevation/artifactdatabase/transition/TransitionEngine.java Fri Sep 28 12:15:12 2012 +0200 @@ -44,7 +44,7 @@ * Add new transitions for a specific artifact. * * @param stateId the name of the Artifact. - * @param transitions the list of transition of the artifact. + * @param transition the list of transition of the artifact. * * @return true, if the transitions were added, otherwise false. */ diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/resources/sql/org-h2-driver.properties --- a/artifact-database/src/main/resources/sql/org-h2-driver.properties Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/resources/sql/org-h2-driver.properties Fri Sep 28 12:15:12 2012 +0200 @@ -33,16 +33,17 @@ users.id.nextval=SELECT NEXTVAL('USERS_ID_SEQ') -users.insert=INSERT INTO users (id, gid, name, role) VALUES (?, ?, ?, ?) +users.insert=INSERT INTO users (id, gid, name, account, role) VALUES (?, ?, ?, ?, ?) users.select.id.by.gid=SELECT id FROM users WHERE gid = ? -users.select.gid=SELECT id, name, role FROM users WHERE gid = ? +users.select.gid=SELECT id, name, account, role FROM users WHERE gid = ? +users.select.account=SELECT gid, name, account, role FROM users WHERE account = ? users.delete.id=DELETE FROM users WHERE id = ? users.delete.collections=DELETE FROM collections where owner_id = ? -users.select.all=SELECT id, gid, name, role FROM users +users.select.all=SELECT id, gid, name, account, role FROM users collection.check.artifact=SELECT id FROM collection_items \ WHERE artifact_id = ? AND collection_id = ? @@ -77,7 +78,7 @@ UPDATE artifacts \ SET last_access = DATEADD('MILLISECOND', -2, CURRENT_TIMESTAMP), ttl = 1 \ WHERE id = ? AND \ - NOT EXSITS \ + NOT EXISTS \ (SELECT id FROM collection_items WHERE collection_id <> ? AND artifact_id = ?) collection.item.delete=DELETE FROM collection_items WHERE id = ? @@ -137,6 +138,11 @@ collection.creation.time=SELECT creation from collections WHERE id = ? +collections.artifacts.oldest=SELECT a.gid, ci.artifact_id \ + FROM artifacts AS a, collection_items AS ci, collections AS c \ + WHERE ci.collection_id = c.id AND c.gid = ?::uuid AND ci.artifact_id = a.id \ + ORDER BY ci.creation + collections.select.user= \ SELECT c.gid, c.name, c.creation, u.gid, c.ttl FROM \ collections c LEFT OUTER JOIN users u ON c.owner_id = u.id \ @@ -163,7 +169,7 @@ outdate.artifacts.collection=UPDATE artifacts \ SET last_access = DATEADD('MILLISECOND', -2, CURRENT_TIMESTAMP), ttl = 1 \ WHERE id IN \ - SELECT artifact_id FROM collection_items \ + (SELECT artifact_id FROM collection_items \ WHERE collection_id = ? AND \ artifact_id NOT IN (SELECT DISTINCT artifact_id FROM collection_items WHERE collection_id <> ?)) diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifact-database/src/main/resources/sql/org-postgresql-driver.properties --- a/artifact-database/src/main/resources/sql/org-postgresql-driver.properties Mon Sep 19 13:55:26 2011 +0000 +++ b/artifact-database/src/main/resources/sql/org-postgresql-driver.properties Fri Sep 28 12:15:12 2012 +0200 @@ -33,16 +33,17 @@ users.id.nextval=SELECT NEXTVAL('USERS_ID_SEQ') -users.insert=INSERT INTO users (id, gid, name, role) VALUES (?, ?::uuid, ?, ?) +users.insert=INSERT INTO users (id, gid, name, account, role) VALUES (?, ?::uuid, ?, ?, ?) users.select.id.by.gid=SELECT id FROM users WHERE gid = ?::uuid -users.select.gid=SELECT id, name, role FROM users WHERE gid = ?::uuid +users.select.gid=SELECT id, name, account, role FROM users WHERE gid = ?::uuid +users.select.account=SELECT gid, name, account, role FROM users WHERE account = ? users.delete.id=DELETE FROM users WHERE id = ? users.delete.collections=DELETE FROM collections where owner_id = ? -users.select.all=SELECT id, gid, name, role FROM users +users.select.all=SELECT id, gid, name, account, role FROM users collection.check.artifact=SELECT id FROM collection_items \ WHERE artifact_id = ? AND collection_id = ? @@ -77,7 +78,7 @@ UPDATE artifacts \ SET last_access = CURRENT_TIMESTAMP - '2 milliseconds'::interval, ttl = 1 \ WHERE id = ? AND \ - NOT EXSITS \ + NOT EXISTS \ (SELECT id FROM collection_items WHERE collection_id <> ? AND artifact_id = ?) collection.item.delete=DELETE FROM collection_items WHERE id = ? @@ -128,6 +129,11 @@ collection.creation.time=SELECT creation from collections WHERE id = ? +collections.artifacts.oldest=SELECT a.gid, ci.artifact_id \ + FROM artifacts AS a, collection_items AS ci, collections AS c \ + WHERE ci.collection_id = c.id AND c.gid = ?::uuid AND ci.artifact_id = a.id \ + ORDER BY ci.creation + collections.select.user= \ SELECT c.gid, c.name, c.creation, u.gid, c.ttl FROM \ collections c LEFT OUTER JOIN users u ON c.owner_id = u.id \ diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifacts-common/src/main/java/de/intevation/artifacts/common/model/KVP.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts-common/src/main/java/de/intevation/artifacts/common/model/KVP.java Fri Sep 28 12:15:12 2012 +0200 @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2010 by Intevation GmbH + * + * This program is free software under the LGPL (>=v2.1) + * Read the file LGPL.txt coming with the software for details + * or visit http://www.gnu.org/licenses/ if it does not exist. + */ +package de.intevation.artifacts.common.model; + + +public class KVP { + + private K key; + private V value; + + + public KVP(K key, V value) { + this.key = key; + this.value = value; + } + + + public K getKey() { + return key; + } + + + public V getValue() { + return value; + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifacts-common/src/main/java/de/intevation/artifacts/common/utils/ClientProtocolUtils.java --- a/artifacts-common/src/main/java/de/intevation/artifacts/common/utils/ClientProtocolUtils.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifacts-common/src/main/java/de/intevation/artifacts/common/utils/ClientProtocolUtils.java Fri Sep 28 12:15:12 2012 +0200 @@ -25,36 +25,47 @@ */ public class ClientProtocolUtils { - /** The XPath to the current state in the DESCRIBE document.*/ + /** The XPath to the current state in the DESCRIBE document. */ public static final String XPATH_CURRENT_STATE = "/art:result/art:state"; - /** The XPath to the static UI part in the DESCRIBE document.*/ + /** The XPath to the static UI part in the DESCRIBE document. */ public static final String XPATH_STATIC = "/art:result/art:ui/art:static"; - /** The XPath to the dynamic UI part in the DESCRIBE document.*/ + /** The XPath to the dynamic UI part in the DESCRIBE document. */ public static final String XPATH_DYNAMIC = "/art:result/art:ui/art:dynamic"; - /** The XPath to the reachable states part in the DESCRIBE document.*/ + /** The XPath to the reachable states part in the DESCRIBE document. */ public static final String XPATH_STATES = "/art:result/art:reachable-states"; - /** The XPath to the output modes in the DESCRIBE document.*/ + /** The XPath to the output modes in the DESCRIBE document. */ public static final String XPATH_OUTPUT_MODES = "/art:result/art:outputmodes/art:output"; - /** The XPath to the select node relative to the dynamic UI node in the - * DESCRIBE document.*/ + * DESCRIBE document. */ public static final String XPATH_DATA_SELECT = "art:select"; /** The XPath to the choices nodes relative to the select node in the - * DESCRIBE document.*/ + * DESCRIBE document. */ public static final String XPATH_DATA_ITEMS = "art:choices/art:item"; - /** The XPath to a label in the artifact's DESCRIBE document.*/ + /** The XPath that points to the min value of a range.*/ + public static final String XPATH_MIN_NODE = "art:min/@art:value"; + + /** The XPath that points to the max value of a range.*/ + public static final String XPATH_MAX_NODE = "art:max/@art:value"; + + /** The XPath that points to the default min value of a range.*/ + public static final String XPATH_DEF_MIN = "art:min/@art:default"; + + /** The XPath that points to the default max value of a range.*/ + public static final String XPATH_DEF_MAX = "art:max/@art:default"; + + /** The XPath to a label in the artifact's DESCRIBE document. */ public static final String XPATH_LABEL = "art:label/text()"; - /** The XPath to a value in the artifact's DESCRIBE document.*/ + /** The XPath to a value in the artifact's DESCRIBE document. */ public static final String XPATH_VALUE = "art:value/text()"; @@ -325,7 +336,7 @@ * collection in the artifact server. * * @param artId The identifier of the artifact that should be added. - * @param attr A document that contains attributes for the attribute's + * @param attr A document that contains attributes for the artifact's * life in the collection. * * @return the document to add an artifact into a collection. @@ -361,6 +372,38 @@ /** + * Create a new Document that is used to remove an artifact from a + * collection in the artifact server. + * + * @param artId The identifier of the artifact that should be added. + * + * @return the document to add an artifact into a collection. + */ + public static Document newRemoveArtifactDocument(String artId) { + Document doc = XMLUtils.newDocument(); + + XMLUtils.ElementCreator cr = new XMLUtils.ElementCreator( + doc, + ArtifactNamespaceContext.NAMESPACE_URI, + ArtifactNamespaceContext.NAMESPACE_PREFIX); + + Element action = cr.create("action"); + Element type = cr.create("type"); + Element artifact = cr.create("artifact"); + + cr.addAttr(artifact, "uuid", artId); + cr.addAttr(type, "name", "removeartifact"); + + action.appendChild(type); + type.appendChild(artifact); + + doc.appendChild(action); + + return doc; + } + + + /** * This method creates a new Document that is used to trigger the DESCRIBE * operation of a collection in the artifact server. * @@ -777,5 +820,41 @@ XPathConstants.NODESET, ArtifactNamespaceContext.INSTANCE); } + + + public static String getMinNode(Node parent) { + return (String) XMLUtils.xpath( + parent, + XPATH_MIN_NODE, + XPathConstants.STRING, + ArtifactNamespaceContext.INSTANCE); + } + + + public static String getMaxNode(Node parent) { + return (String) XMLUtils.xpath( + parent, + XPATH_MAX_NODE, + XPathConstants.STRING, + ArtifactNamespaceContext.INSTANCE); + } + + + public static String getDefMin(Node parent) { + return (String) XMLUtils.xpath( + parent, + XPATH_DEF_MIN, + XPathConstants.STRING, + ArtifactNamespaceContext.INSTANCE); + } + + + public static String getDefMax(Node parent) { + return (String) XMLUtils.xpath( + parent, + XPATH_DEF_MAX, + XPathConstants.STRING, + ArtifactNamespaceContext.INSTANCE); + } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifacts-common/src/main/java/de/intevation/artifacts/common/utils/DateUtils.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts-common/src/main/java/de/intevation/artifacts/common/utils/DateUtils.java Fri Sep 28 12:15:12 2012 +0200 @@ -0,0 +1,30 @@ +package de.intevation.artifacts.common.utils; + +import java.util.Calendar; +import java.util.Date; + + +public class DateUtils { + + private DateUtils() { + } + + + /** + * This function extracts the year as int value from date. + * + * @param date The source date. + * + * @return the year as integer or -1 if date is empty. + */ + public static int getYearFromDate(Date date) { + if (date == null) { + return -1; + } + + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + + return cal.get(Calendar.YEAR); + } +} diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifacts-common/src/main/java/de/intevation/artifacts/common/utils/FileTools.java --- a/artifacts-common/src/main/java/de/intevation/artifacts/common/utils/FileTools.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifacts-common/src/main/java/de/intevation/artifacts/common/utils/FileTools.java Fri Sep 28 12:15:12 2012 +0200 @@ -12,13 +12,19 @@ import java.io.IOException; import java.io.InputStream; import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.OutputStream; +import java.io.BufferedOutputStream; +import java.nio.channels.FileChannel; -import java.util.Stack; +import java.util.Deque; +import java.util.ArrayDeque; import java.util.List; import java.util.Set; import java.util.HashSet; import java.util.ArrayList; +import java.util.Enumeration; +import java.util.zip.ZipFile; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; @@ -62,7 +68,7 @@ if (file.exists()) { return file; } - Stack parts = new Stack(); + Deque parts = new ArrayDeque(); File curr = file; while (curr != null) { String name = curr.getName(); @@ -119,7 +125,7 @@ return curr; } - public static class HashedFile + public static class HashedFile implements Comparable { protected File file; @@ -196,7 +202,7 @@ @Override public boolean equals(Object other) { - return other instanceof HashedFile + return other instanceof HashedFile && ((HashedFile)other).compareTo(this) == 0; } @@ -230,7 +236,7 @@ public static void walkTree(File root, FileVisitor visitor) { - Stack stack = new Stack(); + Deque stack = new ArrayDeque(); stack.push(root); @@ -315,7 +321,7 @@ } else if (file.isDirectory()) { - Stack stack = new Stack(); + Deque stack = new ArrayDeque(); stack.push(new PrefixDir(file.getName() + "/", file)); while (!stack.isEmpty()) { @@ -344,6 +350,57 @@ out.finish(); } + + public static void extractArchive(File archive, File destDir) + throws IOException { + if (!destDir.exists()) { + destDir.mkdir(); + } + + ZipFile zipFile = new ZipFile(archive); + Enumeration entries = zipFile.entries(); + + byte[] buffer = new byte[16384]; + int len; + while (entries.hasMoreElements()) { + ZipEntry entry = (ZipEntry) entries.nextElement(); + + String entryFileName = entry.getName(); + + File dir = dir = buildDirectoryHierarchyFor(entryFileName, destDir); + if (!dir.exists()) { + dir.mkdirs(); + } + + if (!entry.isDirectory()) { + BufferedOutputStream bos = new BufferedOutputStream( + new FileOutputStream(new File(destDir, entryFileName))); + + BufferedInputStream bis = new BufferedInputStream(zipFile + .getInputStream(entry)); + + while ((len = bis.read(buffer)) > 0) { + bos.write(buffer, 0, len); + } + + bos.flush(); + bos.close(); + bis.close(); + } + } + zipFile.close(); + } + + private static File buildDirectoryHierarchyFor( + String entryName, + File destDir) + { + int lastIndex = entryName.lastIndexOf('/'); + String entryFileName = entryName.substring(lastIndex + 1); + String internalPathToEntry = entryName.substring(0, lastIndex + 1); + return new File(destDir, internalPathToEntry); + } + /** * A class representing a directory with a prefix. */ @@ -399,5 +456,134 @@ } out.closeEntry(); } + + + /** + * Copies a src file to target. + * + * @param src A file (not a directory) that should be copied. + * @param target The destination. This might be a file or a directory. + * + * @return true, if src has been successfully copied; otherwise + * false. + */ + public static boolean copyFile(File src, File target) + throws IOException + { + if (src == null || !src.exists()) { + log.warn("Source file does not exist!"); + return false; + } + + if (!src.canRead()) { + log.warn("Cannot read Source file!"); + return false; + } + + if (src.isDirectory()) { + log.warn("Source is a directory!"); + return false; + } + + if (target.isDirectory()) { + target = new File(target, src.getName()); + } + + FileInputStream in = null; + FileOutputStream out = null; + + try { + in = new FileInputStream(src); + out = new FileOutputStream(target); + + FileChannel inChannel = in.getChannel(); + FileChannel outChannel = out.getChannel(); + + inChannel.transferTo(0l, inChannel.size(), outChannel); + + return true; + } + catch (IOException ioe) { + log.warn(ioe, ioe); + } + finally { + if (in != null) { + try { + in.close(); + } + catch (IOException ioe) { /* do nothing here */ } + } + + if (out != null) { + try { + out.close(); + } + catch (IOException ioe) { /* do nothing here */ } + } + } + + return false; + } + + + /** + * Copies a directory source to a destination path dest. + * + * @param source A directory that should be copied. + * @param dest A destination directory which is created if it is not + * existing yet. + * + * @return true, if the directory has been successfully copied; otherwise + * false. + */ + public static boolean copyDirectory(final File source, final File dest) { + if (source == null || !source.exists()) { + log.warn("Source directory does not exist!"); + return false; + } + + if (!source.isDirectory()) { + log.warn("Source is not a directory!"); + return false; + } + + if (dest == null) { + log.warn("Destination directory is null!"); + return false; + } + + if (!dest.exists()) { + if (!dest.mkdir()) { + log.warn("Cannot create destination directory!"); + return false; + } + } + + File[] children = source.listFiles(); + int failed = 0; + + if (children != null && children.length > 0) { + for (File child: children) { + if (child.isFile()) { + try { + if (!copyFile(child, dest)) { + failed++; + } + } + catch (IOException ioe) { + log.warn(ioe, ioe); + failed++; + } + } + else if (child.isDirectory()) { + copyDirectory(child, new File(dest, child.getName())); + } + } + } + + log.debug("Failed to copy " + failed + " files."); + + return true; + } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifacts-common/src/main/java/de/intevation/artifacts/common/utils/JSON.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts-common/src/main/java/de/intevation/artifacts/common/utils/JSON.java Fri Sep 28 12:15:12 2012 +0200 @@ -0,0 +1,445 @@ +package de.intevation.artifacts.common.utils; + +import java.util.Map; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.ArrayList; +import java.util.Iterator; + +import java.io.IOException; +import java.io.PushbackInputStream; +import java.io.InputStream; +import java.io.PrintWriter; +import java.io.ByteArrayInputStream; +import java.io.StringWriter; + +import java.nio.charset.Charset; +import java.nio.charset.UnsupportedCharsetException; + +public final class JSON +{ + private JSON() { + } + + private static final boolean isDigit(int c) { + return c >= '0' && c <= '9'; + } + + public static final boolean isWhitespace(int c) { + return c == ' ' || c == '\n' || c == '\r' + || c == '\t' || c == '\f'; + } + + private static final void match(int c, int x) throws IOException { + if (c != x) { + throw new IOException( + "Expecting '" + (char)c + "' found '" + (char)x + "'"); + } + } + + private static final int eof(InputStream in) + throws IOException + { + int c = in.read(); + if (c == -1) { + throw new IOException("EOF unexpected."); + } + return c; + } + + private static final int whitespace(InputStream in) + throws IOException + { + int c; + while (isWhitespace(c = eof(in))); + return c; + } + + private static final int parseHex(String hex) throws IOException { + try { + return Integer.parseInt(hex, 16); + } + catch (NumberFormatException nfe) { + throw new IOException("'" + hex + "' is not a hex string."); + } + } + + public static final String jsonString(String string) { + StringBuilder sb = new StringBuilder(string.length()+2); + + sb.append('"'); + + for (int i = 0, N = string.length(); i < N; ++i) { + char c = string.charAt(i); + switch (c) { + case '"': sb.append("\\\""); break; + case '\t': sb.append("\\t"); break; + case '\r': sb.append("\\r"); break; + case '\n': sb.append("\\n"); break; + case '\b': sb.append("\\b"); break; + case '\f': sb.append("\\f"); break; + default: + if (c >= 128) { + sb.append("\\u"); + String hex = Integer.toHexString((int)c); + for (int j = 4-hex.length(); j > 0; --j) { + sb.append('0'); + } + sb.append(hex); + } + else { + sb.append(c); + } + } + } + + sb.append('"'); + + return sb.toString(); + } + + public static String toJSONString(Map map) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + write(pw, map); + pw.flush(); + return sw.toString(); + } + + + public static void write(PrintWriter out, Map map) { + writeObject(out, map); + } + + private static void writeValue(PrintWriter out, Object value) { + if (value instanceof Map) { + writeObject(out, (Map)value); + } + else if (value instanceof List) { + writeList(out, (List)value); + } + else if (value instanceof Number) { + out.print(value); + } + else if (value instanceof Boolean) { + out.print(((Boolean)value) ? "true" : "false"); + } + else if (value == null) { + out.print("null"); + } + else { + out.print(jsonString(value.toString())); + } + } + + private static void writeObject(PrintWriter out, Map map) { + + out.print('{'); + Iterator iter = map.entrySet().iterator(); + while (iter.hasNext()) { + Map.Entry entry = (Map.Entry)iter.next(); + out.print(jsonString(entry.getKey().toString())); + out.print(':'); + writeValue(out, entry.getValue()); + if (iter.hasNext()) { + out.print(','); + } + } + out.print('}'); + } + + private static void writeList(PrintWriter out, List list) { + out.print('['); + Iterator iter = list.iterator(); + while (iter.hasNext()) { + writeValue(out, iter.next()); + if (iter.hasNext()) { + out.print(','); + } + } + out.print(']'); + } + + public static Map parse(String in) + throws IOException + { + return parse(asInputStream(in)); + } + + private static InputStream asInputStream(String in) { + byte [] bytes; + try { + bytes = in.getBytes(Charset.forName("US-ASCII")); + } + catch (UnsupportedCharsetException uce) { + // Should not happen. + bytes = in.getBytes(); + } + return new ByteArrayInputStream(bytes); + } + + public static Map parse(InputStream in) + throws IOException + { + return parseObject(new PushbackInputStream(in, 1)); + } + + public static Map parse(PushbackInputStream in) + throws IOException + { + return parseObject(in); + } + + private static final String parseString( + PushbackInputStream in + ) + throws IOException + { + StringBuilder sb = new StringBuilder(); + + int mode = 0; + + char [] hex = new char[4]; + + match('"', eof(in)); + + OUT: for (int c = eof(in);; c = eof(in)) { + + switch (mode) { + case 0: + if (c == '"') { + break OUT; + } + if (c == '\\') { + mode = 1; + } + else { + sb.append((char)c); + } + break; + case 1: + switch (c) { + case 'u': + mode = 2; + continue; + case 'b': + sb.append('\b'); + break; + case 'f': + sb.append('\f'); + break; + case 'n': + sb.append('\n'); + break; + case 'r': + sb.append('\r'); + break; + case 't': + sb.append('\t'); + break; + default: + sb.append((char)c); + } + mode = 0; + break; + case 2: + hex[0] = (char)c; + mode = 3; + break; + case 3: + hex[1] = (char)c; + mode = 4; + break; + case 4: + hex[2] = (char)c; + mode = 5; + break; + case 5: + hex[3] = (char)c; + sb.append((char)parseHex(new String(hex))); + mode = 0; + break; + } + } + return sb.toString(); + } + + private static final Boolean parseTrue(InputStream in) + throws IOException + { + match('t', eof(in)); + match('r', eof(in)); + match('u', eof(in)); + match('e', eof(in)); + return Boolean.TRUE; + } + + private static final Boolean parseFalse(InputStream in) + throws IOException + { + match('f', eof(in)); + match('a', eof(in)); + match('l', eof(in)); + match('s', eof(in)); + match('e', eof(in)); + return Boolean.FALSE; + } + + private static final Object parseNull(InputStream in) + throws IOException + { + match('n', eof(in)); + match('u', eof(in)); + match('l', eof(in)); + match('l', eof(in)); + return null; + } + + private static final Number parseNumber(PushbackInputStream in) + throws IOException + { + StringBuilder sb = new StringBuilder(); + + boolean isInteger = true; + + int c; + OUT: for (;;) { + switch (c = eof(in)) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case '-': case '+': + sb.append((char)c); + break; + case '.': case 'e': case 'E': + isInteger = false; + sb.append((char)c); + break; + default: + in.unread(c); + break OUT; + } + } + + try { + if (isInteger) { + return sb.length() > 9 + ? (Number)Long .valueOf(sb.toString()) + : (Number)Integer.valueOf(sb.toString()); + } + return (Number)Double.valueOf(sb.toString()); + } + catch (NumberFormatException nfe) { + throw new IOException("Not a number '" + sb + "'"); + } + } + + private static List parseList(PushbackInputStream in) + throws IOException + { + List list = new ArrayList(); + match('[', whitespace(in)); + int c = whitespace(in); + if (c == ']') { + return list; + } + + for (;; c = whitespace(in)) { + Object value; + in.unread(c); + switch (c) { + case '{': + value = parseObject(in); + break; + case '[': + value = parseList(in); + break; + case '"': + value = parseString(in); + break; + case 't': + value = parseTrue(in); + break; + case 'f': + value = parseFalse(in); + break; + case 'n': + value = parseNull(in); + break; + default: + value = parseNumber(in); + } + list.add(value); + + if ((c = whitespace(in)) == ']') break; + match(',', c); + } + return list; + } + + private static void parsePair( + PushbackInputStream in, + Map pairs + ) + throws IOException + { + in.unread(whitespace(in)); + String string = parseString(in); + match(':', whitespace(in)); + + Object value; + + int c = whitespace(in); + in.unread(c); + switch (c) { + case '{': + value = parseObject(in); + break; + case '[': + value = parseList(in); + break; + case '"': + value = parseString(in); + break; + case 't': + value = parseTrue(in); + break; + case 'f': + value = parseFalse(in); + break; + case 'n': + value = parseNull(in); + break; + default: + value = parseNumber(in); + } + pairs.put(string, value); + } + + private static Map parseObject(PushbackInputStream in) + throws IOException + { + Map pairs = new LinkedHashMap(); + + int c = whitespace(in); + match('{', c); + + if ((c = whitespace(in)) == '}') { + return pairs; + } + + in.unread(c); + + for (;;) { + parsePair(in, pairs); + + if ((c = whitespace(in)) == '}') { + break; + } + + if (c == '}') break; + match(',', c); + } + + return pairs; + } +} diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifacts-common/src/main/java/de/intevation/artifacts/common/utils/LRUCache.java --- a/artifacts-common/src/main/java/de/intevation/artifacts/common/utils/LRUCache.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifacts-common/src/main/java/de/intevation/artifacts/common/utils/LRUCache.java Fri Sep 28 12:15:12 2012 +0200 @@ -4,7 +4,7 @@ import java.util.LinkedHashMap; public class LRUCache -extends LinkedHashMap +extends LinkedHashMap { public static final int DEFAULT_MAX_CAPACITY = 25; diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifacts-common/src/main/java/de/intevation/artifacts/common/utils/StringUtils.java --- a/artifacts-common/src/main/java/de/intevation/artifacts/common/utils/StringUtils.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifacts-common/src/main/java/de/intevation/artifacts/common/utils/StringUtils.java Fri Sep 28 12:15:12 2012 +0200 @@ -103,5 +103,46 @@ } return sb.toString(); } + + public static final String [] toUpperCase(String [] s) { + if (s == null) { + return null; + } + String [] d = new String[s.length]; + for (int i = 0; i < s.length; ++i) { + if (s[i] != null) { + d[i] = s[i].toUpperCase(); + } + } + return d; + } + + public static String join(String sep, String [] strings) { + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < strings.length; ++i) { + if (i > 0) sb.append(sep); + sb.append(strings[i]); + } + return sb.toString(); + } + + public static final String [] join(String [] a, String [] b) { + if (a == null && b == null) return null; + if (a == null) return b; + if (b == null) return a; + String [] dst = new String[a.length + b.length]; + System.arraycopy(a, 0, dst, 0, a.length); + System.arraycopy(b, 0, dst, a.length, b.length); + return dst; + } + + public static final boolean contains(String needle, String [] haystack) { + for (String stray: haystack) { + if (needle.equals(stray)) { + return true; + } + } + return false; + } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifacts-common/src/main/java/de/intevation/artifacts/common/utils/XMLUtils.java --- a/artifacts-common/src/main/java/de/intevation/artifacts/common/utils/XMLUtils.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifacts-common/src/main/java/de/intevation/artifacts/common/utils/XMLUtils.java Fri Sep 28 12:15:12 2012 +0200 @@ -8,7 +8,10 @@ package de.intevation.artifacts.common.utils; +import java.util.List; +import java.util.ArrayList; import java.util.Map; +import java.util.LinkedHashMap; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; @@ -49,6 +52,7 @@ import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.w3c.dom.Node; import org.xml.sax.SAXException; @@ -59,15 +63,13 @@ */ public final class XMLUtils { - /** - * W3C URL of XForms - */ + /** W3C URL of XForms. */ public static final String XFORM_URL = "http://www.w3.org/2002/xforms"; - /** - * W3C prefix of XForms - */ + + /** W3C prefix of XForms. */ public static final String XFORM_PREFIX = "xform"; + /** Logger for this class. */ private static Logger logger = Logger.getLogger(XMLUtils.class); private XMLUtils() { @@ -79,17 +81,13 @@ */ public static class ElementCreator { - /** - * owner document of the elements to be created - */ + /** Owner document of the elements to be created. */ protected Document document; - /** - * namespace to be used - */ + + /** Namespace to be used. */ protected String ns; - /** - * prefix to be used - */ + + /** Prefix to be used. */ protected String prefix; /** @@ -154,7 +152,6 @@ else { element.setAttribute(name, value); } - } } // class ElementCreator @@ -176,6 +173,20 @@ return null; } + + /** + * Create xml/string representation of element (nested in otherwise empty + * document). + * @param element element to inspect in string. + * @return string with xml representation of element. + */ + public final static String toString(Node node) { + Document doc = newDocument(); + doc.appendChild(doc.importNode(node,true)); + return toString(doc); + } + + /** * Loads a XML document namespace aware from a file * @param file The file to load. @@ -200,9 +211,31 @@ return null; } + /** + * Parses a String to a xml document. + * + * @param string The xml string + * @return the XML document or null if something went wrong. + */ + public static final Document parseDocument(String string) { + InputStream inputStream = new ByteArrayInputStream(string.getBytes()); + return parseDocument(inputStream); + } + + public static final Document parseDocument(InputStream inputStream) { + return parseDocument(inputStream, Boolean.TRUE); + } + + public static final Document parseDocument( + InputStream inputStream, + Boolean namespaceAware + ) { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); - factory.setNamespaceAware(true); + + if (namespaceAware != null) { + factory.setNamespaceAware(namespaceAware.booleanValue()); + } try { return factory.newDocumentBuilder().parse(inputStream); @@ -445,5 +478,140 @@ } return null; } + + private static class BuildResult { + List children; + Map attributes; + BuildResult() { + children = new ArrayList(); + attributes = new LinkedHashMap(); + } + + void setAttributes(Element element) { + for (Map.Entry entry: attributes.entrySet()) { + element.setAttribute(entry.getKey(), entry.getValue()); + } + } + + void finish(Element element) { + setAttributes(element); + for (Node child: children) { + element.appendChild(child); + } + } + + void add(Node node) { + children.add(node); + } + + void add(String key, Object value) { + attributes.put(key, value != null ? value.toString() : "null"); + } + + int numChildren() { + return children.size(); + } + + Node firstChild() { + return children.get(0); + } + } // class BuildResult + + private static BuildResult recursiveBuild( + List list, + Document document + ) { + BuildResult result = new BuildResult(); + for (Object entry: list) { + if (entry instanceof Map) { + BuildResult subResult = recursiveBuild( + (Map)entry, document); + if (subResult.numChildren() == 1) { + result.add(subResult.firstChild()); + } + else { + Element element = document.createElement("map"); + subResult.finish(element); + result.add(element); + } + } + else if (entry instanceof List) { + Element element = document.createElement("list"); + BuildResult subResult = recursiveBuild((List)entry, document); + subResult.finish(element); + result.add(element); + } + else { + Element element = document.createElement("entry"); + element.setAttribute( + "value", + entry != null ? entry.toString() : "null"); + } + } + return result; + } + + private static BuildResult recursiveBuild( + Map map, + Document document + ) { + BuildResult result = new BuildResult(); + + List nodes = new ArrayList(); + for (Map.Entry entry: map.entrySet()) { + Object value = entry.getValue(); + if (value instanceof Map) { + Element element = document.createElement(entry.getKey()); + BuildResult subResult = recursiveBuild( + (Map)value, document); + subResult.finish(element); + result.add(element); + } + else if (value instanceof List) { + Element element = document.createElement(entry.getKey()); + BuildResult subResult = recursiveBuild((List)value, document); + subResult.finish(element); + result.add(element); + } + else { + result.add(entry.getKey(), value); + } + } + return result; + } + + public static Document jsonToXML(String input) { + Document document = newDocument(); + + if (document == null) { + return null; + } + + Map map; + try { + map = JSON.parse(input); + } + catch (IOException ioe) { + logger.error(ioe); + return null; + } + + BuildResult roots = recursiveBuild(map, document); + + int N = roots.children.size(); + + if (N == 1) { + document.appendChild(roots.children.get(0)); + } + else if (N > 1) { + Node root = document.createElement("root"); + for (int i = 0; i < N; ++i) { + root.appendChild(roots.children.get(i)); + } + document.appendChild(root); + } + + return document; + } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifacts-common/src/main/java/de/intevation/artifacts/common/utils/XSLTransformer.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts-common/src/main/java/de/intevation/artifacts/common/utils/XSLTransformer.java Fri Sep 28 12:15:12 2012 +0200 @@ -0,0 +1,73 @@ +package de.intevation.artifacts.common.utils; + +import java.io.InputStream; +import java.io.StringWriter; + +import java.util.HashMap; +import java.util.Map; + +import javax.xml.transform.Source; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerConfigurationException; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; + +import javax.xml.transform.dom.DOMSource; + +import javax.xml.transform.stream.StreamResult; +import javax.xml.transform.stream.StreamSource; + +import org.apache.log4j.Logger; + +import org.w3c.dom.Node; + +public class XSLTransformer { + + private static Logger log = Logger.getLogger(XSLTransformer.class); + + protected Map parameters; + + public XSLTransformer() { + } + + public String transform(Node source, InputStream transform) { + + try { + Source templateSource = new StreamSource(transform); + TransformerFactory xformFactory = + TransformerFactory.newInstance(); + Transformer transformer = + xformFactory.newTransformer(templateSource); + + if (parameters != null) { + for (Map.Entry entry: parameters.entrySet()) { + transformer.setParameter(entry.getKey(), entry.getValue()); + } + } + + StringWriter result = new StringWriter(); + + DOMSource src = new DOMSource(source); + StreamResult dst = new StreamResult(result); + transformer.transform(src, dst); + + return result.toString(); + } + catch (TransformerConfigurationException tce) { + log.error(tce, tce); + } + catch (TransformerException te) { + log.error(te, te); + } + + return null; + } + + public void addParameter(String key, Object value) { + if (parameters == null) { + parameters = new HashMap(); + } + parameters.put(key, value); + } +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifacts/pom.xml --- a/artifacts/pom.xml Mon Sep 19 13:55:26 2011 +0000 +++ b/artifacts/pom.xml Fri Sep 28 12:15:12 2012 +0200 @@ -22,8 +22,8 @@ maven-compiler-plugin 2.0.2 - 1.5 - 1.5 + 1.6 + 1.6 diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifacts/src/main/java/de/intevation/artifacts/ArtifactDatabase.java --- a/artifacts/src/main/java/de/intevation/artifacts/ArtifactDatabase.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifacts/src/main/java/de/intevation/artifacts/ArtifactDatabase.java Fri Sep 28 12:15:12 2012 +0200 @@ -207,7 +207,7 @@ * @throws ArtifactDatabaseException Thrown if someting went wrong during * the service processing. */ - Document process(String service, Document input, CallMeta callMeta) + Service.Output process(String service, Document input, CallMeta callMeta) throws ArtifactDatabaseException; // User API @@ -215,6 +215,9 @@ Document listUsers(CallMeta callMeta) throws ArtifactDatabaseException; + Document findUser(Document data, CallMeta callMeta) + throws ArtifactDatabaseException; + Document createUser(Document data, CallMeta callMeta) throws ArtifactDatabaseException; @@ -223,6 +226,9 @@ // Collection API + Document getCollectionsMasterArtifact(String collectionId, CallMeta meta) + throws ArtifactDatabaseException; + Document listCollections(String userId, CallMeta callMeta) throws ArtifactDatabaseException; diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifacts/src/main/java/de/intevation/artifacts/ArtifactFactory.java --- a/artifacts/src/main/java/de/intevation/artifacts/ArtifactFactory.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifacts/src/main/java/de/intevation/artifacts/ArtifactFactory.java Fri Sep 28 12:15:12 2012 +0200 @@ -13,8 +13,6 @@ import org.w3c.dom.Document; import org.w3c.dom.Node; -import de.intevation.artifacts.GlobalContext; - /** * Interface of an artifact producing factory. diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifacts/src/main/java/de/intevation/artifacts/ArtifactNamespaceContext.java --- a/artifacts/src/main/java/de/intevation/artifacts/ArtifactNamespaceContext.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifacts/src/main/java/de/intevation/artifacts/ArtifactNamespaceContext.java Fri Sep 28 12:15:12 2012 +0200 @@ -86,7 +86,7 @@ */ @Override public String getPrefix(String uri) { - + if (uri == null) { throw new IllegalArgumentException("Null uri"); } diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifacts/src/main/java/de/intevation/artifacts/CallContext.java --- a/artifacts/src/main/java/de/intevation/artifacts/CallContext.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifacts/src/main/java/de/intevation/artifacts/CallContext.java Fri Sep 28 12:15:12 2012 +0200 @@ -9,6 +9,7 @@ package de.intevation.artifacts; import java.util.LinkedList; +import java.util.List; import org.w3c.dom.Document; import org.w3c.dom.Node; @@ -109,7 +110,7 @@ * Each call context has a clipboard. * getContextValue is used to fetch data from this board. * @param key Key of the requested item. - * @return The value stored for the secified value, null if + * @return The value stored for the specified value, null if * no item with this key exists. */ Object getContextValue(Object key); @@ -128,5 +129,17 @@ * @return The time to live of the current artifact. */ Long getTimeToLive(); + + /** + * Get a list of DataProvider that get provide 'key' type of data to + * other facets. + */ + public List getDataProvider(Object key); + + /** + * Register a DataProvider that can provide 'key' type of data to + * other facets. + */ + public Object registerDataProvider(Object key, DataProvider provider); } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifacts/src/main/java/de/intevation/artifacts/DataProvider.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/de/intevation/artifacts/DataProvider.java Fri Sep 28 12:15:12 2012 +0200 @@ -0,0 +1,21 @@ +package de.intevation.artifacts; + +/** + * DataProviders register on a Blackboard with a key (basically shouting + * "I can or know X!"). + * + * Consumers look at the blackboard and then consume data from these + * DataProvider, passing them (optional) parameterization and the blackboard + * itself. + * + * Through the blackboard-passing-when-consuming, also recursive patterns can + * be modelled (but take care, there is no in-built cycle detection). + */ +public interface DataProvider { + /** Register this DataProvider on a blackboard under a key. */ + public void register(CallContext blackboard); + + /** Provide data, given parameterization and a "blackboard". */ + public Object provideData(Object key, Object param, CallContext context); +} +// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifacts/src/main/java/de/intevation/artifacts/Service.java --- a/artifacts/src/main/java/de/intevation/artifacts/Service.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifacts/src/main/java/de/intevation/artifacts/Service.java Fri Sep 28 12:15:12 2012 +0200 @@ -20,14 +20,20 @@ public interface Service extends Serializable { + interface Output { + Object getData(); + + String getMIMEType(); + } // interface Output + /** * Processes some input XML document * @param data The input data * @param globalContext The global context of the artifact database. * @param callMeta The call meta contex, e.g. preferred languages. - * @return The result output XML document. + * @return The result. */ - Document process(Document data, GlobalContext globalContext, CallMeta callMeta); + Output process(Document data, GlobalContext globalContext, CallMeta callMeta); /** * Setup the concrete processing service. This is done at startup time diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifacts/src/main/java/de/intevation/artifacts/User.java --- a/artifacts/src/main/java/de/intevation/artifacts/User.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifacts/src/main/java/de/intevation/artifacts/User.java Fri Sep 28 12:15:12 2012 +0200 @@ -25,5 +25,7 @@ void setRole(Document role); Document getRole(); + + String getAccount(); } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 artifacts/src/main/java/de/intevation/artifacts/UserFactory.java --- a/artifacts/src/main/java/de/intevation/artifacts/UserFactory.java Mon Sep 19 13:55:26 2011 +0000 +++ b/artifacts/src/main/java/de/intevation/artifacts/UserFactory.java Fri Sep 28 12:15:12 2012 +0200 @@ -14,6 +14,7 @@ { void setup(Document config, Node factoryNode); - User createUser(String identifier, String name, Document role, Object context); + User createUser(String identifier, String name, String account, + Document role, Object context); } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : diff -r c53ec9fdc758 -r d01e9f6a3dc1 pom.xml --- a/pom.xml Mon Sep 19 13:55:26 2011 +0000 +++ b/pom.xml Fri Sep 28 12:15:12 2012 +0200 @@ -27,8 +27,8 @@ maven-compiler-plugin 2.0.2 - 1.5 - 1.5 + 1.6 + 1.6