diff --git a/build.properties b/build.properties index 1d576f96c..253b9c5d0 100644 --- a/build.properties +++ b/build.properties @@ -1,79 +1,28 @@ # Ant build properties files for the metacat build -#Version of this build. This needs to be a dotted numeric version. For -#instance 1.9.1 is okay. 1.9.1_rc1 is not. +#Version of this build. Versions are expected to follow Semantic Versioning (https://semver.org/) +# metacat.version=3.3.0 # Release tag for the version of metacatui to bundle with this release # Find the latest version here: https://nceas.github.io/metacatui/install/ +# metacatui.tag=2.36.2 # java source code version and target version for java compilation +# java.target=17 -#This is for packaging purposes. leave it blank for final production release. -metacat.releaseCandidate= - # Tomcat dev deployment directory -# install ant target uses this to determine where to drop -# the war file in an installation. Test classes will use -# this value to find metacat.properties +# install ant target uses this to determine where to drop the war file in an installation. +# Integration Test classes that require a running metacat installation will use this value +# to find metacat.properties +# app.deploy.dir=/opt/local/share/java/tomcat/webapps -# CVS access to retrieve latest EML, seek and utilities -cvsroot=:ext:${env.USER}@cvs.ecoinformatics.org:/cvs - -## metacat.context will be used to name war -metacat.context=metacat -workflowscheduler.context=workflowscheduler -authority.context=authority - -# Server Properties -http.protocol=http -config.lsidauthority=ecoinformatics.org - -# SCW: Set the cgi-user, either here or in scripts to properly -# set the permissions on the temporary folder; cgi-writable files -cgi-user=www-data - -#Turn off or on for timed replication -#valide value is true or false -timedreplication=false - -# The time for starting first timed replication if timedreplication is on -# The value should be in SHORT format (e.g. 2:00 AM) without date -# The first timed replication will start at the setting time which is -# shortest to the tomcat start time. -# Fox example, if the setting is 2:00 AM and tomcat was started at 8:00 AM. -# the first timed replication will start at 2:00 AM in the second day -# If the setting is 2:00 PM and tomcat was started at 8:00 AM, the first -# replication will start at 2:00 PM in the same day. -firsttimedreplication=10:00 PM - -# The interval to next timed replication if timedreplication is on -# The value is in millisecond and default value is 48 hours -timedreplicationinterval=172800000 - -forcereplicationwaitingtime=30000 - -## Additional configuration options -# you probably don't want or need to change these -config.metadataLabelLsid=${config.lsidauthority} +# Additional configuration options - you probably don't want or need to change these +# build.dir=build -lsid.build.dir=${build.dir}/lsid lib.dir=lib lsid.lib.dir=${lib.dir}/lsid_lib -lsid.classes.dir=edu/ucsb/nceas/metacat/lsid -conf.dir=lib/lsid_conf -services.dir=${conf.dir}/services -webinf.dir=${conf.dir}/WEB-INF - -compile.debug=true -compile.deprecation=false -compile.optimize=true - -# Flag to install ecogird or not. Possible values are true or false -install.ecogrid=true -# Flag to make perl code or not. Possible values are true or false -make.perl.code=true diff --git a/build.xml b/build.xml index 9033b54ac..96991dff6 100644 --- a/build.xml +++ b/build.xml @@ -520,7 +520,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/docs/dev/building-metacat.html b/docs/dev/building-metacat.html index 0abaeb910..c796db3aa 100755 --- a/docs/dev/building-metacat.html +++ b/docs/dev/building-metacat.html @@ -68,14 +68,6 @@
  • app.deploy.dir - the automated installation build (install) will deploy your war file for you and clean up old application directories. Make sure this is set to the directory where Tomcat looks for its applications.
  • -
  • cvsroot - if your cvs user is different than the user you are using to build metacat, - you will need to change -
    :ext:${env.USER}@cvs.ecoinformatics.org:/cvs
    - to -
    :ext:<your_cvs_user>@cvs.ecoinformatics.org:/cvs
    - If you do not have a personal account with cvs, you can set the username to - "anonymous". The password will be "guestaccess". -
  • build.xml
    diff --git a/docs/dev/workflowscheduler/createWorkflowSchedulerDB.txt b/docs/dev/workflowscheduler/createWorkflowSchedulerDB.txt deleted file mode 100644 index 8b5a13957..000000000 --- a/docs/dev/workflowscheduler/createWorkflowSchedulerDB.txt +++ /dev/null @@ -1,42 +0,0 @@ -Instructions on initially creating the workflow scheduler database. - -Update postgres configuration - Edit: - /etc/postgresql//main/pg_hba.conf - Add the following Line: - host workflowscheduler workflowscheduler 127.0.0.1 255.255.255.255 password - -Create database: - type: createdb workflowscheduler - -Create workflowscheduler user - Log in to postgreSQL by typing: - psql workflowscheduler - At the psql prompt, create the workflowscheduler user by typing: - CREATE USER workflowscheduler WITH UNENCRYPTED PASSWORD 'your_password'; - where 'your_password' is whatever password you would like for the workflowscheduler user. - Exit PostgreSQL by typing: - \q - Restart the PostgreSQL database to bring in changes: - /etc/init.d/postgresql-8.3 restart - -Test setup - Log out of the postgres user account by typing: - logout - Test the installation and workflowscheduler account by typing: - psql -U workflowscheduler -W -h localhost workflowscheduler - -Create tables: - Open the table creation script at: - /src/scripts/workflowscheduler-db-scripts/ws-tables-postgres.sql - Copy each sql command and run in psql prompt. - - Or at the psql prompt, type "\i /src/scripts/workflowscheduler-db-scripts/ws-tables-postgres.sql" - -Populate tables - Open the table creation script at: - /src/scripts/workflowscheduler-db-scripts/ws-loaddtdschema-postgres.sql - Copy each sql command and run in psql prompt. - - Or at the psql prompt, type "\i /src/scripts/workflowscheduler-db-scripts/ws-loaddtdschema-postgres.sql" - diff --git a/docs/dev/workflowscheduler/installWorkflowScheduler.txt b/docs/dev/workflowscheduler/installWorkflowScheduler.txt deleted file mode 100644 index 77f8ecc50..000000000 --- a/docs/dev/workflowscheduler/installWorkflowScheduler.txt +++ /dev/null @@ -1,62 +0,0 @@ -These are the steps to install the workflow scheduler, workflow run engine and kepler. -At the time of this writing, the workflow scheduler is associated with a single instance -of metacat. The workflow run engine and kepler are installed on the same machine as the -workflow scheduler. - -These instructions assume that you already have a working copy of apache and tomcat. - -Build the workflow scheduler: - -- check out Metacat trunk code - -- in the root directory, run "ant clean war -f workflowscheduler.build.xml" - -- the workflowsheduler.war file will be in ./workflowscheduler.dist/ - -Deploy the workflow scheduler: - -- copy the workflowscheduler.war file to the tomcat webapp directory on the target - server - -- unjar the war file so you can modify the configuration - -- in the webapp dir, mkdir workflowscheduler - -- cd workflowscheduler - -- jar -xvf ../workflowscheduler.war - -- vi WEB-INF/workflowscheduler.properties - -- change the workflowScheduler.authServiceUrl and - workflowScheduler.authorizationServiceUrl to point to the instance of metacat - associated with the scheduler. - -Create the database: - -- follow the instructions in the following file in this directory: - createWorkflowSchedulerDB.txt - -Configure Metacat: - -- on the instance of Metacat associated with this workflowscheduler, edit - WEB-INF/metacat.properties - -- change the workflowScheduler.url to point to the workflow scheduler server - -Restart: - -- Restart the tomcat instance for the scheduler and for metacat. - -Install R - -- follow the instructions at: http://cran.r-project.org/doc/manuals/R-admin.html - to download and install r - -- for rhel4, the following steps were applied - -- download source tar.gz at: - http://cran.cnr.berkeley.edu/sources.html - -- tar -xvzf R-2.10.0.tar.gz - -- install gcc: up2date gcc-g77 - -- run configure with no x and no readline options - ./configure --with-x=no --with-readline=no - -- run "make" - -- run "make install" - -Install kepler: - -- mkdir /usr/kepler - -- cd /usr/kepler - -- svn co https://code.kepler-project.org/code/kepler/trunk/modules/build-area - -- cd build-area - -- ant change-to -Dsuite=wrp - -- ant run - -- close kepler - -- ant startup-script - -Install workflow run engine: - -- follow the steps listed in: - http://code.kepler-project.org/code/kepler/trunk/modules/webservice/KeplerWebService/doc/kepler-execution-engine-installation.txt diff --git a/lib/certificateAuthenCode/MetacatGsiClient.java b/lib/certificateAuthenCode/MetacatGsiClient.java deleted file mode 100644 index 55bf5e1dc..000000000 --- a/lib/certificateAuthenCode/MetacatGsiClient.java +++ /dev/null @@ -1,112 +0,0 @@ -package edu.ucsb.nceas.metacat.client.gsi; - -import edu.ucsb.nceas.metacat.client.MetacatAuthException; -import edu.ucsb.nceas.metacat.client.MetacatClient; -import edu.ucsb.nceas.metacat.client.MetacatInaccessibleException; -import edu.ucsb.nceas.utilities.HttpMessage; -import org.ietf.jgss.GSSCredential; - -import java.io.IOException; -import java.net.MalformedURLException; -import java.net.URL; -import java.net.URLStreamHandler; -import java.util.Properties; - -/** An extension of the Metacat client that uses Grid Security Infrastructure - * (GSI) enabled HTTPS instead of HTTP to communicate. - * - *

    Note that not all client deployments will include the JARs necessary to - * run this version of the Metacat client; therefore, we should make sure that - * the superclass (MetacatClient) can run even if this class can't be loaded. - * That is, catch (and log) NoClassDefFoundError, etc. */ -public class MetacatGsiClient extends MetacatClient { - - /** The current user's GSS credential, as an alternative to - * username/password. Needed for every connection. - * Set via {@link #login(GSSCredential)}. */ - private GSSCredential credential; - - private void initCredential(GSSCredential credential) - throws MetacatAuthException - { - if (credential == null) - throw new NullPointerException("Credential is null."); - if (this.credential != null) - throw new MetacatAuthException - ("Credential already initialized; please create a new " - + getClass().getName() + " to start a new session."); - this.credential = credential; - } - - public String login(GSSCredential credential) - throws MetacatAuthException, MetacatInaccessibleException - { - initCredential(credential); - - // code below mostly copied from super.login(username, password) - Properties prop = new Properties(); - prop.put("action", "login"); - prop.put("qformat", "xml"); - - String response; - try { - response = sendDataForString(prop, null, null, 0); - } catch (Exception e) { - throw new MetacatInaccessibleException(e); - } - - if (response.indexOf("") == -1) { - setSessionId(""); - throw new MetacatAuthException(response); - } else { - int start = response.indexOf("") + 11; - int end = response.indexOf(""); - if ((start != -1) && (end != -1)) { - setSessionId(response.substring(start,end)); - } - } - return response; - } - - /** Parse the Metacat URL and, if we are using a GSI credential, - * ensure that the protocol is an SSL-based one (HTTPS or HTTPG). */ - private URL parseAndCheckURL() throws MetacatInaccessibleException { - try { - URL url = new URL(getMetacatUrl().trim()); - - if (credential != null) { - URLStreamHandler gsiHandler; - try { - gsiHandler = (URLStreamHandler) Class - .forName("org.globus.net.protocol.https.Handler") - .newInstance(); - } catch (Exception e) { - throw new MetacatInaccessibleException - ("Unable to create protocol handler for HTTPS+GSI.", e); - } - // reconstruct with correct handler - url = new URL(url.getProtocol(), url.getHost(), url.getPort(), - url.getFile(), gsiHandler); - } - return url; - } - catch (MalformedURLException e) { - throw new MetacatInaccessibleException - ("Unable to parse URL to contact Metacat server: \"" - + getMetacatUrl() + "\".", e); - } - } - - /** Create an HttpMessage that can send messages to the server. - * If using a GSI credential, use the credential to set up an SSL - * connection (HTTPS / HTTPG). If using HTTP and username/password, - * just use a regular HTTP conenction. */ - protected HttpMessage createHttpMessage() - throws MetacatInaccessibleException, MetacatAuthException, IOException - { - if (credential != null) - return new HttpGsiMessage(credential, parseAndCheckURL()); - else - return super.createHttpMessage(); - } -} diff --git a/lib/certificateAuthenCode/READE.txt b/lib/certificateAuthenCode/READE.txt deleted file mode 100644 index 760212547..000000000 --- a/lib/certificateAuthenCode/READE.txt +++ /dev/null @@ -1,49 +0,0 @@ -metacat_additions.tar.gz, MetacatGsiClient.java, bbaker_diff_metacat.txt and bbaker_diff_utilities.txt files came from Bill Baker at UIUC. His work is part of effort on Pilot project. Baker's work focused on making Metacat support HTTPS+GSI (Grid Security Infrastructure) POST. - -Here are the emails from Baker: - ----------- Forwarded message ---------- -Date: Mon, 17 Oct 2005 14:42:28 -0500 -From: Bill Baker -To: Jing Tao -Cc: Matt Jones , Saurabh Garg , - Von Welch , mfreemon@ncsa.uiuc.edu -Subject: Re: Notes for Metacat Call - -I just found a way to simplify the HTTPS+GSI protocol handling in Java, while I was writing some documentation -- I'm surprised I didn't see it before, -because it's just the use of a different URL constructor. As a bonus, it should eliminate the compile dependency on JGlobus JARs. - -The change is: - -(1) delete the class edu.ucsb.nceas.protocols.httpg -- it - is no longer necesary -(2) update MetacatGSIClient.java (attached) - -I tested it out in the LTER grid pilot project app and ran some unit tests, and it seems to work fine. - --- Bill - -At 14:19 2005-10-06, Bill Baker wrote: -Here, finally, are my Metacat diffs. I've included three files: - - bbaker_diff_metacat.txt -- a cvs diff of the metacat module - bbaker_diff_utilities.txt -- a cvs diff of the utilities module - metacat_additions.tar.gz -- the files that I have added to metacat,in the directories where they belong in the metacat module - -As for our unit tests, the easiest way to get them is probably to download from CVS, at :pserver:anonymous@cvs.ncsa.uiuc.edu/CVS/grids -- check out -the LTERPilotApp module, which has classes MetacatTest, which has GSI login tests and some simple queries with GSI authentication, and -MetacatQueryTest, which does more complex querying. -You may also find the metacat CVS module helpful -- it has our changes and a few extra Ant scripts for easy Metacat deployment in our particular -configuration, as seen on Roadrunner. - -Bill Baker wrote: -An update on the Metacat patches that I'm working on: -I'm working on getting some changes into JGlobus to support HTTPS+GSI POST (it only supported GET before), including new support for streaming -data -- my previous additions to it buffered the entire POST in memory before transmitting. Once I finish with that, I plan to package up the -Metacat changes and send them to you. -I have a question: unit tests. We wrote some unit tests for the LTER Grid pilot project that covered HTTPS+GSI, but they are outside of the -Metacat unit testing framework. They only tested logging in and querying over HTTPS+GSI -- not harvesting or any of the update/delete -operations. I'll include those tests when I send you my diffs. Do you think you'll want to work them into Metacat's unit tests? --- Bill - - diff --git a/lib/certificateAuthenCode/bbaker_diff_metacat.txt b/lib/certificateAuthenCode/bbaker_diff_metacat.txt deleted file mode 100644 index ae1c51761..000000000 --- a/lib/certificateAuthenCode/bbaker_diff_metacat.txt +++ /dev/null @@ -1,3421 +0,0 @@ -? lib/gsi -? lib/cog-url-ncsa.jar -? lib/cog-jglobus-ncsa.jar -? src/gsimap.properties -? src/edu/ucsb/nceas/metacat/AuthGsi.java -? src/edu/ucsb/nceas/metacat/AuthInfo.java -? src/edu/ucsb/nceas/metacat/GsiMapfile.java -? src/edu/ucsb/nceas/metacat/client/gsi -Index: build.properties -=================================================================== -RCS file: /cvs/metacat/build.properties,v -retrieving revision 1.16 -diff -r1.16 build.properties -85a86,100 -> -> # Authentication options -- written into metacat.properties -> # can be "Gsi" or "Ldap" -> auth-method=Gsi -> # can really only be "Ldap" for now -> auth-delegate=Ldap -> # can be "true" or "false" -> auth-delegation-allowed=true -> # can be "username+password" or "gss" -> auth-precedence=username+password -> -> # Should logins from localhost with no password be trusted? Useful -> # for the GT4 web service wrapper around metacat when it isn't using -> # GSI delegation. -> auth-trust-localhost=true -Index: build.xml -=================================================================== -RCS file: /cvs/metacat/build.xml,v -retrieving revision 1.226 -diff -r1.226 build.xml -273a274,278 -> -> -> -> -> -Index: docs/user/metacatinstall.html -=================================================================== -RCS file: /cvs/metacat/docs/user/metacatinstall.html,v -retrieving revision 1.20 -diff -r1.20 metacatinstall.html -20a21,28 -> -618a627,917 -> -> -> -> -> -> ->
    ->

    GSI (Grid Security Infrastructure) Authentication

    ->
    ->

    Overview

    -> ->

    -> As an alternative to username/password, Metacat can use Grid -> Security Infrastructure (GSI) credentials for authentication, if -> you are programming to the Metacat client API. The advantages -> are: ->

    -> ->
      ->
    • -> Use of security credentials enables sign-on with other grid -> services. ->
    • ->
    • -> Metacat's plaintext HTTP client-server connection is replaced -> with encrypted HTTPS+GSI -- that is, SSL HTTP using grid -> security credentials for the SSL connection. ->
    • ->
    -> -> ->

    Grid Security Setup

    -> ->
      ->
    1. ->

      If you don't have any Grid infrastructure available already, -> you can href="http://grid.ncsa.uiuc.edu/myproxy/fromscratch.html">follow -> these instructions to get started from scratch.

      ->
    2. -> ->
    3. ->

      Establish host credentials for your Metacat server. The -> instructions above will suffice for experimentation, or you can -> get host credentials from your own Certificate Authority. You -> can always replace them in the future.

      ->
    4. ->
    -> ->

    Tomcat Configuration

    -> ->
      ->
    1. -> ->

      Add JARs to Tomcat's $CATALINA_HOME/common/lib -> directory. You can find them in the Metacat distribution in -> metacat/lib/gsi:

      -> ->
      -> cog-jglobus-ncsa.jar, commons-pool-1.2.jar, -> cryptix32.jar, cryptix-asn1.jar, cryptix.jar, -> jce-jdk13-125.jar, jgss.jar, log4j-1.2.8.jar, puretls.jar, -> xml-apis.jar ->
      -> ->

      Note that cog-jglobus-ncsa.jar is a modified -> version of cog-jglobus.jar which comes with the href="http://www.globus.org/toolkit/">Globus Toolkit. It -> includes a patch to enable GSI+HTTPS POST actions (only GET was -> supported previously). The patch has been committed to the CoG -> source and will be included in a future a version of the Globus -> Toolkit, but until then you will need this custom JAR.

      -> ->
    2. -> ->
    3. ->

      Modify Tomcat's server.xml to listen for -> HTTPS+GSI. Note that you can use any available port for this -> connector; this example uses 8443.

      -> ->

      Host credentials: The HTTPS connection will require host -> credentials for the Metacat server; the example below assumes -> that the host credentials are in -> /etc/grid-security, which is the default location -> for a Globus -> toolkit installation.

      -> ->

      CA Cert Dir: Any Certificate Authorities (CAs) that you -> depend on -- for example, the one that issued your host -> credential -- should have their public keys and signing policies -> stored in a location that is accessible to Tomcat -> (cacertdir, below). The filenames will be -> something like 4a6cd8b1.0 and -> 4a6cd8b1.signing_policy.

      -> ->
        -> ->
      • ->

        Add an HTTPSConnector, inside the -> <Service name="Catalina"> section, near -> the SSL HTTP/1.1 connector definition, which is commented -> out by default:

        -> ->
        -> <!-- Define a SSL HTTP/1.1 Connector on port 8443 -->
        -> <!--
        -> <Connector port="8443" maxHttpHeaderSize="8192"
        ->            maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
        ->            enableLookups="false" disableUploadTimeout="true"
        ->            acceptCount="100" scheme="https" secure="true"
        ->            clientAuth="false" sslProtocol="TLS" />
        -> -->
        -> 
        -> <!-- Define an HTTPS+GSI (HTTPS with GSI credentials) Connector on port 8443 -->
        -> <Connector className="org.globus.tomcat.coyote.net.HTTPSConnector"
        ->            port="8443" maxThreads="150" minSpareThreads="25" maxSpareThreads="75" 
        ->            autoFlush="true" disableUploadTimeout="true" scheme="https"
        ->            enableLookups="true" acceptCount="10" debug="0" 
        ->            cert="/etc/grid-security/hostcert.pem"
        ->            key="/etc/grid-security/hostkey.pem"
        ->            cacertdir="/etc/grid-security/certificates"/>
        -> 
        ->
      • ->
      • ->

        Add an HTTPSValve, inside the <Engine -> name="Catalina" ...> section, near the -> RequestDumperValve definition, which is -> commented out by default:

        -> ->
        -> <!--
        -> <Valve className="org.apache.catalina.valves.RequestDumperValve"/>
        -> -->
        -> 
        -> <!-- Globus valve for HTTPS+GSI -->
        -> <Valve className="org.globus.tomcat.coyote.valves.HTTPSValve"/>
        -> 
        ->
      • ->
      ->
    4. -> ->
    5. ->

      Restart Tomcat -- it should now be listening for HTTPS+GSI -> connections. Watch for errors in its log file -> ($CATALINA_HOME/logs/catalina.out).

      ->
    6. ->
    -> ->

    Metacat Client GSI Login

    -> ->
      ->
    1. ->

      You can now use GSI credentials to initiate a Metacat -> session, replacing Metacat.login(String username, String -> password) with Metacat.login(GSSCredential -> credential). There are several ways to get a -> GSSCredential; one easy method, if you have access -> to a MyProxy -> server, is to use the CoG -> Java libraries to retrieve a proxy credential from MyProxy.

      -> ->

      Here is some sample Java code. Note that it requires, in -> addition to the JARs listed above, -> cog-url-ncsa.jar, which can be found in the -> metacat/lib directory.

      -> ->

      Note: for code comments, mouse over the title="like this one">marked sections below.

      -> ->
      -> // 1. Get a GSI security credential
      -> org.globus.myproxy.MyProxy server = new MyProxy(host, 7512);
      -> org.ietf.jgss.GSSCredential credential = server.get(username, passphrase, lifetime);
      -> 
      -> // 2. Connect to Metacat via GSI+HTTPS
      -> String metacatUrl = "https://<metacat server>:8443/metacat/metacat/";
      -> edu.ucsb.nceas.metacat.client.Metacat client 
      ->     = edu.ucsb.nceas.metacat.client.MetacatFactory.createMetacatConnection(metacatUrl);
      -> String loginResult = client.login(credential);
      -> 
      -> ->

      The String returned by -> Metacat.login(GSSCredential) will let you know -> whether your attempt succeeded.

      ->
    2. -> ->
    3. ->

      In order to give GSI users privileges in Metacat, you must -> Map GSI user IDs, or Distinguished Names (DNs), to Metacat user -> IDs, which will generally be LDAP DNs. You can do this in a map -> file that starts out in -> metacat/src/gsimap.properties and gets deployed to -> Tomcat's webapps/metacat/WEB-INF/ directory. You can -> modify it in either place, but it will be overwritten each time -> you redeploy Metacat if you change it in Tomcat's installation -> directory.

      ->
    4. ->
    -> ->

    A Client Inside of Tomcat

    -> ->

    Detailed explanation: The sample code above will work in a simple -> testing situation such as in an IDE's debugger, and it may work in a -> desktop application, but it won't work inside Tomcat. It has two -> problems, both of which have to do with Java's protocol handling -> facilities. The first problem is a protocol handler collision -- -> Tomcat has already instantiated an HTTPS handler, and it is not the -> one we need for GSI+HTTPS. The second problem has to do with class -> loading: our special HTTPS protocol handlers are not accessible to -> Java's protocol handling code because they are not loaded by -> Tomcat's root classloader.

    -> ->
      ->
    1. -> You will most likely need to install the Metacat server and the -> Metacat client application in separate instances of -> Tomcat in order for them to successfully connect. ->
    2. -> ->
    3. ->

      Protocol Handler Collisions:

      -> ->

      Short answer: replace "https" with -> "httpg".

      ->
      https://<metacat server>:8443/metacat/metacat/
      ->

      becomes

      ->
      httpg://<metacat server>:8443/metacat/metacat/
      -> ->

      Long answer: The URL in the example above, -> https://<metacat server>:8443/metacat/metacat/, -> uses the HTTPS protocol. However, actually -> handling that connection requires a protocol handler that -> understands GSI+HTTPS instead of plain HTTPS. Fortunately, -> static initialization code in -> MetacatGsiClient specifies a non-default -> HTTPS handler before the default handler is -> instantiated by Java.

      -> ->

      Unfortunately, in Tomcat, an HTTPS handler has -> already been instantiated by the time Metacat code runs, and we -> don't have a chance to instantiate our special handler. -> Besides, other applications also running in Tomcat may need to -> use the default handler.

      -> ->

      Instead, we can define a new protocol. It could be named -> anything -- HTTPGSI, METACAT_GSI, -> GRID_HTTP, etc. Metacat defines a handler for a -> protocol named HTTPG. To see how it works, see the -> static initialization code in -> edu.ucsb.nceas.metacat.client.MetacatGsiClient and -> the very simple class -> edu.ucsb.nceas.protocols.httpg.Handler.

      ->
    4. ->
    5. ->

      Tomcat Classloading: Since the Java classes that dynamically -> load protocol handlers are in Tomcat's root classloader, the -> protocol handlers themselves must be there also.

      -> ->
        ->
      1. -> Copy metacat.jar, utilities.jar, -> and cog-url-ncsa.jar from Metacat's lib -> directory to a place that is accessible by Tomcat, such as -> $CATALINA_HOME/common/lib. ->
      2. ->
      3. ->

        Modify the definition of CLASSPATH in -> Tomcat's startup script, -> $CATALINA_HOME/bin/catalina.sh (In Windows, -> catalina.bat, which has slightly different -> syntax).

        -> ->

        Replace:

        ->
        -> CLASSPATH="$CLASSPATH":"$CATALINA_HOME"/bin/bootstrap.jar:\
        -> "$CATALINA_HOME"/bin/commons-logging-api.jar
        -> 
        ->

        With:

        ->
        -> CLASSPATH="$CLASSPATH":"$CATALINA_HOME"/bin/bootstrap.jar:\
        -> "$CATALINA_HOME"/bin/commons-logging-api.jar:"$CATALINA_HOME"/common/lib/metacat.jar:\
        -> "$CATALINA_HOME"/common/lib/utilities.jar:"$CATALINA_HOME"/common/lib/cog-url-ncsa.jar
        -> 
        ->
      4. ->
      -> -> ->
    6. ->
    ->
    -> -Index: lib/metacat.properties -=================================================================== -RCS file: /cvs/metacat/lib/metacat.properties,v -retrieving revision 1.100 -diff -r1.100 metacat.properties -43,54d42 -< moderators=@moderators@ -< -< allowedSubmitters=@allowedSubmitters@ -< -< deniedSubmitters=@deniedSubmitters@ -< -< timedreplication=@timedreplication@ -< -< firsttimedreplication=@firsttimedreplication@ -< -< timedreplicationinterval=@timedreplicationinterval@ -< -89,90d76 -< indexed_paths=organizationName,originator/individualName/surName,originator/individualName/givenName,originator/organizationName,creator/individualName/surName,creator/individualName/givenName,creator/organizationName,dataset/title,keyword,northBoundingCoordinate,southBoundingCoordinate,westBoundingCoordinate,eastBoundingCoordinate,title,entityName,individualName/surName,abstract/para,surName,givenName,para,geographicDescription,literalLayout -< -97c83,88 -< authclass=edu.ucsb.nceas.metacat.AuthLdap ---- -> authclass=edu.ucsb.nceas.metacat.Auth@auth-method@ -> authDelegateClass=edu.ucsb.nceas.metacat.Auth@auth-delegate@ -> authDelegationAllowed=@auth-delegation-allowed@ -> authPrecedence=@auth-precedence@ -> gsiMapClass=edu.ucsb.nceas.metacat.GsiMapfile -> trustLocalHost=@auth-trust-localhost@ -99c90,91 -< ldapurl=ldap://ldap.ecoinformatics.org:389/ ---- -> #ldapurl=ldap://ldap.ecoinformatics.org:389/ -> ldapurl=ldap://ldap.lternet.edu/ -101c93,94 -< ldapsurl=ldap://ldap.ecoinformatics.org:389/ ---- -> #ldapsurl=ldap://ldap.ecoinformatics.org:389/ -> ldapsurl=ldap://ldap.lternet.edu/ -103c96,97 -< ldapbase=dc=ecoinformatics,dc=org ---- -> #ldapbase=dc=ecoinformatics,dc=org -> ldapbase=o=lter,dc=ecoinformatics,dc=org -Index: src/edu/ucsb/nceas/metacat/AuthInterface.java -=================================================================== -RCS file: /cvs/metacat/src/edu/ucsb/nceas/metacat/AuthInterface.java,v -retrieving revision 1.7 -diff -r1.7 AuthInterface.java -46,48c46,47 -< * @param user the name of the principal to authenticate -< * @param password the password to use for authentication -< * @returns boolean true if authentication successful, false otherwise ---- -> * @param info authentication information from the user -> * @return true if authentication successful, false otherwise -50c49 -< public boolean authenticate(String user, String password) ---- -> public boolean authenticate(AuthInfo info) -56c55 -< public String[][] getUsers(String user, String password) ---- -> public String[][] getUsers(AuthInfo info) -62c61 -< public String[] getUsers(String user, String password, String group) ---- -> public String[] getUsers(AuthInfo info, String group) -68c67 -< public String[][] getGroups(String user, String password) ---- -> public String[][] getGroups(AuthInfo info) -74c73 -< public String[][] getGroups(String user, String password, String foruser) ---- -> public String[][] getGroups(AuthInfo info, String foruser) -80,81c79,80 -< * @param user the user for which the attribute list is requested -< * @returns HashMap a map of attribute name to a Vector of values ---- -> * @param foruser the user for which the attribute list is requested -> * @return a map of attribute name to a Vector of values -89,92c88,90 -< * @param user the user for which the attribute list is requested -< * @param authuser the user for authenticating against the service -< * @param password the password for authenticating against the service -< * @returns HashMap a map of attribute name to a Vector of values ---- -> * @param info authentication information to use to access the directory -> * @param foruser the user for which the attribute list is requested -> * @return a map of attribute name to a Vector of values -94c92 -< public HashMap getAttributes(String user, String password, String foruser) ---- -> public HashMap getAttributes(AuthInfo info, String foruser) -100,101c98,99 -< * @param user the user which requests the information -< * @param password the user's password ---- -> * @param info authentication information about the user who requests the -> * information -103c101 -< public String getPrincipals(String user, String password) ---- -> public String getPrincipals(AuthInfo info) -Index: src/edu/ucsb/nceas/metacat/AuthLdap.java -=================================================================== -RCS file: /cvs/metacat/src/edu/ucsb/nceas/metacat/AuthLdap.java,v -retrieving revision 1.55 -diff -r1.55 AuthLdap.java -31a32,33 -> import javax.naming.*; -> import javax.naming.directory.*; -33,49d34 -< import javax.naming.AuthenticationException; -< import javax.naming.Context; -< import javax.naming.NamingEnumeration; -< import javax.naming.NamingException; -< import javax.naming.SizeLimitExceededException; -< import javax.naming.InitialContext; -< import javax.naming.directory.InvalidSearchFilterException; -< import javax.naming.directory.Attribute; -< import javax.naming.directory.Attributes; -< import javax.naming.directory.BasicAttribute; -< import javax.naming.directory.BasicAttributes; -< import javax.naming.directory.DirContext; -< import javax.naming.directory.InitialDirContext; -< import javax.naming.directory.SearchResult; -< import javax.naming.directory.SearchControls; -< import javax.naming.ReferralException; -< import javax.naming.ldap.*; -51,56c36 -< import java.util.Iterator; -< import java.util.HashMap; -< import java.util.Hashtable; -< import java.util.Enumeration; -< import java.util.Set; -< import java.util.Vector; ---- -> import java.util.*; -66d45 -< private MetaCatUtil util = new MetaCatUtil(); -73,76c52 -< private Context rContext; -< private String userName; -< private String userPassword; -< ReferralException refExc; ---- -> ReferralException refExc; -94,96c70,71 -< * @param user the name of the principal to authenticate -< * @param password the password to use for authentication -< * @returns boolean true if authentication successful, false otherwise ---- -> * @param info authentication information from the user -> * @return true if authentication successful, false otherwise -98c73 -< public boolean authenticate(String user, String password) throws ---- -> public boolean authenticate(AuthInfo info) throws -100,104c75,76 -< String ldapUrl = this.ldapUrl; -< String ldapsUrl = this.ldapsUrl; -< String ldapBase = this.ldapBase; -< boolean authenticated = false; -< String identifier = user; ---- -> boolean authenticated = false; -> String identifier = info.getUsername(); -110c82 -< authenticated = ldapAuthenticate(identifier, password); ---- -> authenticated = ldapAuthenticate(identifier, info.getPassword()); -119,120c91,92 -< String refUrl = ""; -< String refBase = ""; ---- -> String refUrl; -> String refBase; -132c104 -< authenticated = ldapAuthenticate(identifier, password, ---- -> authenticated = ldapAuthenticate(identifier, info.getPassword(), -138c110 -< authenticated = ldapAuthenticate(identifier, password); ---- -> authenticated = ldapAuthenticate(identifier, info.getPassword()); -171c143 -< ConnectException, NamingException, NullPointerException { ---- -> NamingException, NullPointerException { -185c157 -< ConnectException, NamingException, NullPointerException { ---- -> NamingException, NullPointerException { -191,192c163,164 -< userName = identifier; -< userPassword = password; ---- -> // userName = identifier; -> // userPassword = password; -220,221d191 -< this.ldapUrl = ldapUrl; -< this.ldapBase = ldapBase; -272c242 -< * @returns String the identifying name for the user, ---- -> * @return String the identifying name for the user, -423,425c393 -< * @param user the user for authenticating against the service -< * @param password the password for authenticating against the service -< * @returns string array of all of the user names ---- -> * @return string array of all of the user names -427c395 -< public String[][] getUsers(String user, String password) throws ---- -> public String[][] getUsers(AuthInfo info) throws -429c397 -< String[][] users = null; ---- -> String[][] users; -460c428 -< Attributes tempAttr = null; ---- -> Attributes tempAttr; -508c476 -< users[i][3] = (String) uorg.elementAt(i); ---- -> users[i][3] = (String) uou.elementAt(i); -529,530c497 -< * @param user the user for authenticating against the service -< * @param password the password for authenticating against the service ---- -> * @param info represents the user making the request -532c499 -< * @returns string array of the user names belonging to the group ---- -> * @return string array of the user names belonging to the group -534c501 -< public String[] getUsers(String user, String password, String group) throws ---- -> public String[] getUsers(AuthInfo info, String group) throws -536c503 -< String[] users = null; ---- -> String[] users; -564d530 -< ; -596,598c562,563 -< * @param user the user for authenticating against the service -< * @param password the password for authenticating against the service -< * @returns string array of the group names ---- -> * @param info represents the user making the request -> * @return string array of the group names -600c565 -< public String[][] getGroups(String user, String password) throws ---- -> public String[][] getGroups(AuthInfo info) throws -602c567 -< return getGroups(user, password, null); ---- -> return getGroups(info, null); -608,609c573 -< * @param user the user for authenticating against the service -< * @param password the password for authenticating against the service ---- -> * @param info represents the user making the request -611c575 -< * @returns string array of the group names ---- -> * @return string array of the group names -613c577 -< public String[][] getGroups(String user, String password, String foruser) throws ---- -> public String[][] getGroups(AuthInfo info, String foruser) throws -617c581 -< Attributes tempAttr = null; ---- -> Attributes tempAttr; -620,621c584,585 -< userName = user; -< userPassword = password; ---- -> // userName = user; -> // userPassword = password; -640c604 -< String filter = null; ---- -> String filter; -708c672 -< String filter = null; ---- -> String filter; -768c732 -< * @returns HashMap a map of attribute name to a Vector of values ---- -> * @return HashMap a map of attribute name to a Vector of values -771c735 -< return getAttributes(null, null, foruser); ---- -> return getAttributes(null, foruser); -777,778c741 -< * @param user the user for authenticating against the service -< * @param password the password for authenticating against the service ---- -> * @param info represents the user making the request -780c743 -< * @returns HashMap a map of attribute name to a Vector of values ---- -> * @return HashMap a map of attribute name to a Vector of values -782c745 -< public HashMap getAttributes(String user, String password, String foruser) throws ---- -> public HashMap getAttributes(AuthInfo info, String foruser) throws -785,787d747 -< String ldapUrl = this.ldapUrl; -< String ldapBase = this.ldapBase; -< String userident = foruser; -837,838c797 -< private Hashtable getSubtrees(String user, String password, -< String ldapUrl, String ldapBase) throws ---- -> private Hashtable getSubtrees(String ldapUrl, String ldapBase) throws -886c845 -< String attrName = (String) attr.getID(); ---- -> String attrName = attr.getID(); -891c850 -< String refName = (String) attr.getID(); ---- -> String refName = attr.getID(); -946,947c905 -< * @param user the user which requests the information -< * @param password the user's password ---- -> * @param info Auth Info representing the user who requests the information -949c907 -< public String getPrincipals(String user, String password) throws ---- -> public String getPrincipals(AuthInfo info) throws -952c910,911 -< ---- -> Vector usersIn = new Vector(); -> -960,961c919 -< Hashtable subtrees = getSubtrees(user, password, this.ldapUrl, -< this.ldapBase); ---- -> Hashtable subtrees = getSubtrees(this.ldapUrl, this.ldapBase); -963c921 -< Enumeration keyEnum = subtrees.keys(); ---- -> Enumeration keyEnum = subtrees.keys(); -1002,1003c960,961 -< String[][] groups = getGroups(user, password); -< String[][] users = getUsers(user, password); ---- -> String[][] groups = getGroups(info); -> String[][] users = getUsers(info); -1012c970 -< String[] usersForGroup = getUsers(user, password, groups[i][0]); ---- -> String[] usersForGroup = getUsers(info, groups[i][0]); -1014c972,973 -< ---- -> usersIn.addElement(usersForGroup[j]); -> -1042a1002 -> if (!usersIn.contains(users[j][0])) { -1053a1014 -> } -1056a1018,1022 -> if (!usersIn.isEmpty()) { -> usersIn.removeAllElements(); -> usersIn.trimToSize(); -> } -> -1087c1053 -< boolean isValid = false; ---- -> boolean isValid; -1090c1056,1057 -< isValid = authservice.authenticate(user, password); ---- -> AuthInfo info = new AuthInfo(user, password); -> isValid = authservice.authenticate(info); -1101c1068 -< HashMap userInfo = authservice.getAttributes(user, password, user); ---- -> HashMap userInfo = authservice.getAttributes(info, user); -1103c1070 -< Iterator attList = (Iterator) ( ( (Set) userInfo.keySet()).iterator()); ---- -> Iterator attList = userInfo.keySet().iterator(); -1118c1085 -< String[][] groups = authservice.getGroups(user, password); ---- -> String[][] groups = authservice.getGroups(info); -1129c1096 -< String[][] groups = authservice.getGroups(user, password, user); ---- -> String[][] groups = authservice.getGroups(info, user); -1141c1108 -< String[] users = authservice.getUsers(user, password, savedGroup); ---- -> String[] users = authservice.getUsers(info, savedGroup); -1151c1118 -< String[][] users = authservice.getUsers(user, password); ---- -> String[][] users = authservice.getUsers(info); -1160c1127 -< String out = authservice.getPrincipals(user, password); ---- -> String out = authservice.getPrincipals(info); -1186c1153 -< DirContext refDirContext = null; ---- -> DirContext refDirContext; -1188c1155 -< String referralInfo = null; ---- -> String referralInfo; -1202,1203c1169,1170 -< //MetaCatUtil.logMetacat.info("Processing referral (pr1.info): " + userName,35); -< //MetaCatUtil.logMetacat.info("Processing referral (pr2)",35); ---- -> //MetaCatUtil.logMetacat.info("Processing referral (pr1.info): " + userName); -> //MetaCatUtil.logMetacat.info("Processing referral (pr2)"); -1205c1172 -< rContext = refExc.getReferralContext(); ---- -> Context rContext = refExc.getReferralContext(); -1251d1217 -< DirContext refDirContext = null; -1258,1259c1224 -< String refInfo = null; -< refInfo = (String) refExc.getReferralInfo(); ---- -> String refInfo = (String) refExc.getReferralInfo(); -1262c1227 -< refInfo.toString()); ---- -> refInfo); -Index: src/edu/ucsb/nceas/metacat/AuthSession.java -=================================================================== -RCS file: /cvs/metacat/src/edu/ucsb/nceas/metacat/AuthSession.java,v -retrieving revision 1.18 -diff -r1.18 AuthSession.java -30,31d29 -< import java.net.ConnectException; -< import javax.servlet.http.HttpSession; -32a31,32 -> import javax.servlet.http.HttpSession; -> import java.net.ConnectException; -41c41 -< private String authClass = null; ---- -> -52,54c52,86 -< MetaCatUtil util = new MetaCatUtil(); -< this.authClass = util.getOption("authclass"); -< this.authService = (AuthInterface)createObject(authClass); ---- -> String authClass = MetaCatUtil.getOption("authclass"); -> this.authService = (AuthInterface)createObject(authClass); -> -> if (authService instanceof AuthGsi) { -> // special config options for GSI authentication -> String authDelegateClass = MetaCatUtil.getOption("authDelegateClass"); -> String gsiMapClass = MetaCatUtil.getOption("gsiMapClass"); -> String authDelegationAllowed = MetaCatUtil.getOption("authDelegationAllowed"); -> String authPrecedence = MetaCatUtil.getOption("authPrecedence"); -> -> AuthGsi gsi = (AuthGsi) authService; -> if (authDelegateClass != null) { -> AuthInterface delegate = (AuthInterface) createObject(authDelegateClass); -> gsi.setDelegate(delegate); -> } -> if (gsiMapClass != null) { -> GsiToUsernameMap map = (GsiToUsernameMap) createObject(gsiMapClass); -> gsi.setDnMap(map); -> } -> if (authDelegationAllowed != null) { -> boolean allowed = Boolean.valueOf(authDelegationAllowed).booleanValue(); -> if (!allowed && !authDelegationAllowed.trim().toLowerCase().equals("false")) -> MetaCatUtil.logMetacat.warn("Config error: authDelegationAllowed " -> + "must be \"true\" or \"false\" (found \"" -> + authDelegationAllowed + "\"."); -> gsi.setAuthnDelegationAllowed(allowed); -> } -> if (authPrecedence != null) { -> try { -> gsi.setPrecedence(authPrecedence); -> } catch(IllegalArgumentException e) { -> System.err.println(e.getMessage()); -> } -> } -> } -70,71c102 -< * @param username the username entered when login -< * @param password the password entered when login ---- -> * @param info info from the user, such as username and password -73,77c104,107 -< public boolean authenticate(HttpServletRequest request, -< String username, String password) { -< String message = null; -< try { -< if ( authService.authenticate(username, password) ) { ---- -> public boolean authenticate(HttpServletRequest request, AuthInfo info) { -> String message; -> try { -> if ( authService.authenticate(info) ) { -79c109 -< // getGroups returns groupname along with their description. ---- -> // getGroups returns groupname along with their description. -82c112 -< authService.getGroups(username,password,username); ---- -> authService.getGroups(info,info.getUsername()); -93c123 -< this.session = createSession(request, username, password, groups); ---- -> this.session = createSession(request, info, groups); -95c125 -< message = "Authentication successful for user: " + username; ---- -> message = "Authentication successful for user: " + info; -99c129 -< message = "Authentication failed for user: " + username; ---- -> message = "Authentication failed for user: " + info; -104c134,135 -< message = "Connection to the authentication service failed in " + ---- -> ce.printStackTrace(); -> message = "Connection to the authentication service failed in " + -107c138,139 -< message = ise.getMessage(); ---- -> ise.printStackTrace(); -> message = ise.getMessage(); -114,116c146,147 -< /** Get new HttpSession and store username & password in it */ -< private HttpSession createSession(HttpServletRequest request, -< String username, String password, ---- -> /** Get new HttpSession and store authentication info in it */ -> private HttpSession createSession(HttpServletRequest request, AuthInfo info, -129c160 -< session.getAttribute("username")); ---- -> session.getAttribute("auth")); -137,138c168 -< session.setAttribute("username", username); -< session.setAttribute("password", password); ---- -> session.setAttribute("auth", info); -145c175 -< session.getAttribute("username")); ---- -> session.getAttribute("auth")); -161,162c191 -< * @param user the user which requests the information -< * @param password the user's password ---- -> * @param info represents the user who requests the information -164c193 -< public String getPrincipals(String user, String password) ---- -> public String getPrincipals(AuthInfo info) -167c196 -< return authService.getPrincipals(user, password); ---- -> return authService.getPrincipals(info); -210c239 -< Object object = null; ---- -> Object object; -Index: src/edu/ucsb/nceas/metacat/MetaCatServlet.java -=================================================================== -RCS file: /cvs/metacat/src/edu/ucsb/nceas/metacat/MetaCatServlet.java,v -retrieving revision 1.226 -diff -r1.226 MetaCatServlet.java -30,35c30 -< import java.io.BufferedInputStream; -< import java.io.File; -< import java.io.FileInputStream; -< import java.io.IOException; -< import java.io.PrintWriter; -< import java.io.StringReader; ---- -> import java.io.*; -37a33,34 -> import java.net.URLEncoder; -> import java.net.URLDecoder; -44,48c41,42 -< import java.util.Enumeration; -< import java.util.Hashtable; -< import java.util.Iterator; -< import java.util.PropertyResourceBundle; -< import java.util.Vector; ---- -> import java.util.*; -> import java.util.regex.PatternSyntaxException; -52,55c46 -< import javax.servlet.ServletConfig; -< import javax.servlet.ServletContext; -< import javax.servlet.ServletException; -< import javax.servlet.ServletOutputStream; ---- -> import javax.servlet.*; -60a52,53 -> import edu.ucsb.nceas.utilities.Options; -> -61a55 -> import org.ietf.jgss.GSSContext; -68,69d61 -< import edu.ucsb.nceas.utilities.Options; -< -164c156 -< ---- -> -166c158 -< ---- -> -181,182c173,174 -< LOG_CONFIG_NAME = dirPath + "/log4j.properties"; -< ---- -> LOG_CONFIG_NAME = dirPath + "/log4j.properties"; -> -213,214d204 -< } catch (ServletException ex) { -< throw ex; -235d224 -< -237c226,230 -< handleGetOrPost(request, response); ---- -> try { handleGetOrPost(request, response); } -> catch(RuntimeException e) { -> e.printStackTrace(); -> throw new ServletException(e); -> } -244d236 -< -246c238,242 -< handleGetOrPost(request, response); ---- -> try { handleGetOrPost(request, response); } -> catch(RuntimeException e) { -> e.printStackTrace(); -> throw new ServletException(e); -> } -248a245,255 -> /** Copied from org.globus.axis.gsi.GSIConstants, so that we can avoid -> * a compile dependency. */ -> private static final String -> GSI_CREDENTIALS = "org.globus.gsi.credentials", -> GSI_AUTHORIZATION = "org.globus.gsi.authorization", -> GSI_MODE = "org.globus.gsi.mode", -> GSI_AUTH_USERNAME = "org.globus.gsi.authorized.user.name", -> GSI_USER_DN = "org.globus.gsi.authorized.user.dn", -> GSI_ANONYMOUS = "org.globus.gsi.anonymous", -> GSI_CONTEXT = "org.globus.gsi.context"; -> -388d394 -< -403c409,410 -< connPool.printMethodNameHavingBusyDBConnection(); ---- -> if (connPool != null) -> connPool.printMethodNameHavingBusyDBConnection(); -415a423,438 -> Enumeration headerNames = request.getHeaderNames(); -> while (headerNames.hasMoreElements()) { -> String headerName = (String) headerNames.nextElement(); -> } -> -> // check whether incoming connection is via GSI-enabled HTTPS -> // these constants are available from GSIConstants, but not imported -> // here, to avoid dependencies -> GSSContext gsiContext = (GSSContext) request.getAttribute(GSI_CONTEXT); -> String gsiUserDN = (String) request.getAttribute(GSI_USER_DN); -> boolean gssConnection = gsiContext != null && gsiUserDN != null; -> if (gssConnection) { -> params.put(GSI_CONTEXT, gsiContext); -> params.put(GSI_USER_DN, gsiUserDN); -> } -> -433a457,499 -> // Get extra POST parameters because when the incoming request uses -> // chunked coding, they don't automatically get parsed. -> if ("application/x-www-form-urlencoded".equals(ctype)) { -> try { -> String post = readInputStreamAsString(request); -> if (post != null && post.length() > 0) { -> String[] posts = post.split("&"); -> for (int i = 0; i < posts.length; ++i) { -> String[] a = posts[i].split("="); -> for (int j = 0; j < a.length; ++j) -> a[j] = URLDecoder.decode(a[j]); -> if (a.length >= 2) { -> addToMultimap(params, a[0], a[1]); -> } -> } -> } -> } catch(Exception e) { -> String msg = "Exception reading remaining POST data: " -> + e.getMessage(); -> if (MetaCatUtil.debugMessage(msg, 20)) -> e.printStackTrace(); -> } -> } -> -> String[] usernames = (String[]) params.get("username"), -> passwords = (String[]) params.get("password"); -> String username = (usernames != null && usernames.length > 0) -> ? usernames[0] : null; -> String password = (passwords != null && passwords.length > 0) -> ? passwords[0] : null; -> // if no other identifiers, set username to "public" (anonymous) -> if (username == null && gsiUserDN == null) -> username = "public"; -> AuthInfo authInfo = new AuthInfo -> (username, password, gsiContext, gsiUserDN, request); -> -> for (Iterator i = params.keySet().iterator(); i.hasNext();) { -> String key = (String) i.next(); -> Object val = params.get(key); -> if (val == null) val = "null"; -> if (!(val instanceof Object[])) val = new Object[] { val }; -> } -> -456,457d521 -< String username = null; -< String password = null; -464c528 -< handleLoginAction(out, params, request, response); ---- -> handleLoginAction(out, authInfo, params, request, response); -476d539 -< boolean success = false; -478,482c541,543 -< // pool -< //size is greater than initial value, shrink the connection -< // pool -< //size to initial value -< success = DBConnectionPool.shrinkConnectionPoolSize(); ---- -> //pool size is greater than initial value, shrink the -> //connection pool size to initial value -> boolean success = DBConnectionPool.shrinkConnectionPoolSize(); -496c557,573 -< if (sess.isNew() && !params.containsKey("sessionid")) { ---- -> boolean newSession = sess.isNew() && !params.containsKey("sessionid"); -> if (authInfo.getGssContext() != null) { -> // if using GSI for authentication, we lose our session -> // each time, so we have to re-authenticate; fortunately -> // we have enough information to do so -> try { -> AuthSession authSession = new AuthSession(); -> authSession.authenticate(request, authInfo); -> // call it a continuing session -> newSession = false; -> } catch (Exception e) { -> throw new ServletException -> ("Unable to authenticate based on GSI credentials: " -> + e.getMessage(), e); -> } -> } -> if (newSession) { -499a577 -> authInfo = new AuthInfo("public", null); -501c579 -< sess.setAttribute("username", username); ---- -> sess.setAttribute("auth", authInfo); -524c602 -< * sess.getAttribute("username") + " into session ---- -> * sess.getAttribute("auth") + " into session -535c613,614 -< username = (String) sess.getAttribute("username"); ---- -> authInfo = (AuthInfo) sess.getAttribute("auth"); -> username = authInfo.getUsername(); -538d616 -< password = (String) sess.getAttribute("password"); -543c621,623 -< if (username == null || (username.trim().equals(""))) { ---- -> if ((username == null || (username.trim().equals(""))) -> && gsiContext == null ) -> { -544a625,626 -> authInfo = new AuthInfo(username, null); -> sess.setAttribute("auth", authInfo); -619c701 -< handleGetPrincipalsAction(out, username, password); ---- -> handleGetPrincipalsAction(out, authInfo); -646c728 -< } else if (action.equals("login") || action.equals("logout")) { ---- -> } else if (action.equals("login") || action.equals("logout"), groupnames) { -709a792,841 -> /** Assume that map's keys are objects and its values are arrays. */ -> private void addToMultimap(Map params, String key, String value) { -> if (params.containsKey(key)) { -> String[] oldArray; -> Object old = params.get(key); -> if (old instanceof String[]) oldArray = (String[]) old; -> else { -> oldArray = new String[1]; -> oldArray[0] = String.valueOf(old); -> } -> String[] newArray = new String[oldArray.length + 1]; -> System.arraycopy(oldArray, 0, newArray, 0, oldArray.length); -> newArray[newArray.length - 1] = value; -> params.put(key, newArray); -> } -> else params.put(key, new String[] { value }); -> } -> -> private static final int READ_CHUNK_SIZE = 1024; -> -> private String readInputStreamAsString(HttpServletRequest request) -> throws IOException -> { -> ServletInputStream in = request.getInputStream(); -> List byteses = new ArrayList(); -> int total = 0; -> while(true) { -> byte[] k = new byte[READ_CHUNK_SIZE]; -> int n = in.read(k); -> if (n <= 0) break; -> else { -> if (n < READ_CHUNK_SIZE) { -> byte[] k2 = new byte[n]; -> System.arraycopy(k, 0, k2, 0, n); -> k = k2; -> } -> total += n; -> byteses.add(k); -> } -> } -> byte[] all = new byte[total]; -> int start = 0; -> for (int i = 0; i < byteses.size(); i++) { -> byte[] k = (byte[]) byteses.get(i); -> System.arraycopy(k, 0, all, start, k.length); -> start += k.length; -> } -> return new String(all); -> } -> -715c847 -< private void handleLoginAction(PrintWriter out, Hashtable params, ---- -> private void handleLoginAction(PrintWriter out, AuthInfo info, Hashtable params, -719c851 -< AuthSession sess = null; ---- -> AuthSession sess; -721c853 -< if(params.get("username") == null){ ---- -> if(info.getUsername() == null && info.getGssContext() == null){ -730c862,864 -< if(params.get("password") == null){ ---- -> if(info.getPassword() == null && info.getGssContext() == null -> && !info.isLocal()) -> { -739,741c873,874 -< String un = ((String[]) params.get("username"))[0]; -< MetaCatUtil.debugMessage("user " + un + " try to login", 20); -< String pw = ((String[]) params.get("password"))[0]; ---- -> MetaCatUtil.debugMessage -> ("user " + info.toString(true) + " try to login", 20); -756c889,890 -< boolean isValid = sess.authenticate(request, un, pw); ---- -> -> boolean isValid = sess.authenticate(request, info); -763c897 -< + "which has username" + session.getAttribute("username") ---- -> + "which has username" + session.getAttribute("auth") -807c941 -< + sess.getAttribute("username") ---- -> + sess.getAttribute("auth") -941,943c1075,1077 -< "attachment; filename=" -< + docId + ".zip"); // Set the name of the zip file -< ---- -> "attachment; filename=" -> + docId + ".zip"); // Set the name of the zip file -> -1357c1491 -< ---- -> -1642c1776 -< ---- -> -1644c1778 -< out.println(""); ---- -> out.println(""); -2169,2170c2303 -< private void handleGetPrincipalsAction(PrintWriter out, String user, -< String password) ---- -> private void handleGetPrincipalsAction(PrintWriter out, AuthInfo info) -2174c2307 -< String principals = auth.getPrincipals(user, password); ---- -> String principals = auth.getPrincipals(info); -2478,2479c2611 -< String username = null; -< String password = null; ---- -> AuthInfo auth = null; -2485a2618 -> // TODO: don't do this if GSI, since session will be new every time -2487,2488c2620,2621 -< username = "public"; -< sess.setAttribute("username", username); ---- -> auth = new AuthInfo("public", null); -> sess.setAttribute("auth", auth); -2490,2491c2623 -< username = (String) sess.getAttribute("username"); -< password = (String) sess.getAttribute("password"); ---- -> auth = (AuthInfo) sess.getAttribute("auth"); -2512,2513c2644,2645 -< if (username != null && !username.equals("public")) { -< handleUploadAction(request, out, params, fileList, username, ---- -> if (auth != null && !"public".equals(auth.getUsername())) { -> handleUploadAction(request, out, params, fileList, auth.getUsername(), -2909c3041 -< ---- -> -Index: src/edu/ucsb/nceas/metacat/client/Metacat.java -=================================================================== -RCS file: /cvs/metacat/src/edu/ucsb/nceas/metacat/client/Metacat.java,v -retrieving revision 1.14 -diff -r1.14 Metacat.java -26a27,28 -> import org.ietf.jgss.GSSCredential; -> -54c56,88 -< /** ---- -> /** -> *

    Log in to a Metacat server using a Grid Security Infrastructure (GSI) -> * credential to establish an HTTPS connection. Instead of authenticating -> * the user via username and password, the user's identity will be -> * extracted from the credential's Distinguished Name (DN).

    -> * -> *

    Note that some installations will not have the necessary libraries to -> * run GSI, and therefore we need to be able to run the non-GSI Metacat -> * client even if those JARs are absent -- catching NoClassDefFoundError, -> * etc.

    -> * -> * @return the response string from metacat in XML format -> * @throws MetacatAuthException when the client certificate is missing or -> * is not trusted or represents a user who is unknown or not authorized to -> * log in, or if the underlying connection is HTTP instead of HTTPS. -> * @throws UnsupportedOperationException if this client does not support -> * GSI-HTTPS. -> */ -> public String login(GSSCredential credential) -> throws MetacatAuthException, MetacatInaccessibleException; -> -> /** -> * Log in over a trusted connection (usually localhost HTTP) with just -> * a username to identify the user. The server will only allow this login -> * method if it is configured to fully trust incoming connections from this -> * client. -> * -> *

    This may be used, depending on the server's configuration, with -> * a PKI Distinguished Name (DN), or with an LDAP name.

    -> */ -> public String login(String username) throws MetacatInaccessibleException, MetacatAuthException; -> -> /** -148d181 -< * @param xmlDocument a Reader for accessing the document to be inserted -238c271 -< * @returns the sessionId as a String, or null if the session is invalid ---- -> * @return the sessionId as a String, or null if the session is invalid -248c281 -< * @param String the sessionId from a previously established session ---- -> * @param sessionId the session ID from a previously established session -Index: src/edu/ucsb/nceas/metacat/client/MetacatClient.java -=================================================================== -RCS file: /cvs/metacat/src/edu/ucsb/nceas/metacat/client/MetacatClient.java,v -retrieving revision 1.18 -diff -r1.18 MetacatClient.java -27,36d26 -< import java.io.BufferedReader; -< import java.io.InputStream; -< import java.io.InputStreamReader; -< import java.io.PushbackReader; -< import java.io.IOException; -< import java.io.StringWriter; -< import java.io.Reader; -< import java.net.URL; -< import java.util.Properties; -< -39c29,34 -< import java.io.File; ---- -> import edu.ucsb.nceas.metacat.client.gsi.MetacatGsiClient; -> import org.ietf.jgss.GSSCredential; -> -> import java.io.*; -> import java.net.URL; -> import java.util.Properties; -49,50c44,45 -< /** The URL string for the metacat server */ -< private String metacatUrl; ---- -> /** The URL string for the metacat server */ -> private String metacatUrl; -52,53c47,48 -< /** The session identifier for the session */ -< private String sessionId; ---- -> /** The session identifier for the session */ -> private String sessionId; -55,802c50,839 -< /** -< * Constructor to create a new instance. Protected because instances -< * should only be created by the factory MetacatFactory. -< */ -< protected MetacatClient() -< { -< this.metacatUrl = null; -< this.sessionId = null; -< } -< -< /** -< * Method used to log in to a metacat server. Implementations will need -< * to cache a cookie value to make the session persistent. Each time a -< * call is made to one of the other methods (e.g., read), the cookie will -< * need to be passed back to the metacat server along with the request. -< * -< * @param username the username of the user, like an LDAP DN -< * @param password the password for that user for authentication -< * @return the response string from metacat in XML format -< * @throws MetacatAuthException when the username/password could -< * not be authenticated -< */ -< public String login(String username, String password) -< throws MetacatAuthException, MetacatInaccessibleException -< { -< Properties prop = new Properties(); -< prop.put("action", "login"); -< prop.put("qformat", "xml"); -< prop.put("username", username); -< prop.put("password", password); -< -< String response = null; -< try { -< response = sendDataForString(prop, null, null, 0); -< } catch (Exception e) { -< throw new MetacatInaccessibleException(e.getMessage()); -< } -< -< if (response.indexOf("") == -1) { -< setSessionId(""); -< throw new MetacatAuthException(response); -< } else { -< int start = response.indexOf("") + 11; -< int end = response.indexOf(""); -< if ((start != -1) && (end != -1)) { -< setSessionId(response.substring(start,end)); -< } -< } -< return response; -< } -< -< /** -< * Method used to log out a metacat server. The Metacat server will end -< * the session when this call is invoked. -< * -< * @return the response string from metacat in XML format -< * @throws MetacatInaccessibleException when the metacat server can not be -< * reached or does not respond -< */ -< public String logout() throws MetacatInaccessibleException, MetacatException -< { -< Properties prop = new Properties(); -< prop.put("action", "logout"); -< prop.put("qformat", "xml"); -< -< String response = null; -< try { -< response = sendDataForString(prop, null, null, 0); -< } catch (Exception e) { -< throw new MetacatInaccessibleException(e.getMessage()); -< } -< -< if (response.indexOf("") == -1) { -< throw new MetacatException(response); -< } -< setSessionId(""); -< return response; -< } -< -< /** -< * Read an XML document from the metacat server session, accessed by docid, -< * and returned as a Reader. -< * -< * @param docid the identifier of the document to be read -< * @return a Reader for accessing the document -< * @throws InsufficientKarmaException when the user has insufficent rights -< * for the operation -< * @throws MetacatInaccessibleException when the metacat server can not be -< * reached or does not respond -< * @throws MetacatException when the metacat server generates another error -< */ -< public Reader read(String docid) throws InsufficientKarmaException, -< MetacatInaccessibleException, MetacatException -< { -< PushbackReader pbr = null; -< -< Properties prop = new Properties(); -< prop.put("action", "read"); -< prop.put("qformat", "xml"); -< prop.put("docid", docid); -< -< InputStream response = null; -< try { -< response = sendData(prop, null, null, 0); -< } catch (Exception e) { -< throw new MetacatInaccessibleException(e.getMessage()); -< } -< -< pbr = new PushbackReader(new InputStreamReader(response), 512); -< try { -< char[] characters = new char[512]; -< int len = pbr.read(characters, 0, 512); -< StringWriter sw = new StringWriter(); -< sw.write(characters, 0, len); -< String message = sw.toString(); -< sw.close(); -< pbr.unread(characters, 0, len); -< -< if (message.indexOf("") != -1) { -< if (message.indexOf("does not have permission") != -1) { -< throw new InsufficientKarmaException(message); -< } else { -< throw new MetacatException(message); -< } -< } -< } catch (IOException ioe) { -< throw new MetacatException( -< "MetacatClient: Error converting Reader to String." -< + ioe.getMessage()); -< } -< -< return pbr; -< } -< -< -< /** -< * Read inline data from the metacat server session, accessed by -< * inlinedataid and returned as a Reader. -< * -< * @param inlinedataid the identifier of the data to be read -< * @return a Reader for accessing the document -< * @throws InsufficientKarmaException when the user has insufficent rights -< * for the operation -< * @throws MetacatInaccessibleException when the metacat server can not be -< * reached or does not respond -< * @throws MetacatException when the metacat server generates another error -< */ -< public Reader readInlineData(String inlinedataid) -< throws InsufficientKarmaException, -< MetacatInaccessibleException, MetacatException -< { -< PushbackReader pbr = null; -< -< Properties prop = new Properties(); -< prop.put("action", "readinlinedata"); -< prop.put("inlinedataid", inlinedataid); -< -< InputStream response = null; -< try { -< response = sendData(prop, null, null, 0); -< } catch (Exception e) { -< throw new MetacatInaccessibleException(e.getMessage()); -< } -< -< pbr = new PushbackReader(new InputStreamReader(response), 512); -< try { -< char[] characters = new char[512]; -< int len = pbr.read(characters, 0, 512); -< StringWriter sw = new StringWriter(); -< sw.write(characters, 0, len); -< String message = sw.toString(); -< sw.close(); -< pbr.unread(characters, 0, len); -< -< if (message.indexOf("") != -1) { -< if (message.indexOf("does not have permission") != -1) { -< throw new InsufficientKarmaException(message); -< } else { -< throw new MetacatException(message); -< } -< } -< } catch (IOException ioe) { -< throw new MetacatException( -< "MetacatClient: Error converting Reader to String." -< + ioe.getMessage()); -< } -< -< return pbr; -< } -< -< /** -< * Query the metacat document store with the given metacat-compatible -< * query document, and return the result set as a Reader. -< * -< * @param xmlQuery a Reader for accessing the XML version of the query -< * @return a Reader for accessing the result set -< */ -< public Reader query(Reader xmlQuery) throws MetacatInaccessibleException, -< IOException -< { -< Reader reader = null; -< String query = null; -< try { -< query = IOUtil.getAsString(xmlQuery, true); -< } catch (IOException ioE) { -< throw ioE; -< } -< -< //set up properties -< Properties prop = new Properties(); -< prop.put("action", "squery"); -< prop.put("qformat", "xml"); -< prop.put("query", query); -< -< InputStream response = null; -< try { -< response = sendData(prop, null, null, 0); -< } catch (Exception e) { -< throw new MetacatInaccessibleException(e.getMessage()); -< } -< reader = new InputStreamReader(response); -< return reader; -< } -< -< /** -< * Insert an XML document into the repository. -< * -< * @param docid the docid to insert the document -< * @param xmlDocument a Reader for accessing the XML document to be inserted -< * @param schema a Reader for accessing the DTD or XML Schema for -< * the document -< * @return the metacat response message -< * @throws InsufficientKarmaException when the user has insufficent rights -< * for the operation -< * @throws MetacatInaccessibleException when the metacat server can not be -< * reached or does not respond -< * @throws MetacatException when the metacat server generates another error -< * @throws IOException when there is an error reading the xml document -< */ -< public String insert(String docid, Reader xmlDocument, Reader schema) -< throws InsufficientKarmaException, MetacatException, IOException, -< MetacatInaccessibleException -< { -< Reader reader = null; -< String doctext = null; -< String schematext = null; -< try { -< doctext = IOUtil.getAsString(xmlDocument, true); -< if (schema != null) { -< schematext = IOUtil.getAsString(schema, true); -< } -< } catch (IOException ioE) { -< throw ioE; -< } -< -< //set up properties -< Properties prop = new Properties(); -< prop.put("action", "insert"); -< prop.put("docid", docid); -< prop.put("doctext", doctext); -< if (schematext != null) { -< prop.put("dtdtext", schematext); -< } -< -< String response = null; -< try { -< response = sendDataForString(prop, null, null, 0); -< } catch (Exception e) { -< throw new MetacatInaccessibleException(e.getMessage()); -< } -< -< // Check for an error condition -< if (response.indexOf("") != -1) { -< if (response.indexOf("does not have permission") != -1) { -< throw new InsufficientKarmaException(response); -< } else { -< throw new MetacatException(response); -< } -< } -< -< return response; -< } -< -< /** -< * Update an XML document in the repository. -< * -< * @param docid the docid to update -< * @param xmlDocument a Reader for accessing the XML text to be updated -< * @param schema a Reader for accessing the DTD or XML Schema for -< * the document -< * @return the metacat response message -< * @throws InsufficientKarmaException when the user has insufficent rights -< * for the operation -< * @throws MetacatInaccessibleException when the metacat server can not be -< * reached or does not respond -< * @throws MetacatException when the metacat server generates another error -< * @throws IOException when there is an error reading the xml document -< */ -< public String update(String docid, Reader xmlDocument, Reader schema) -< throws InsufficientKarmaException, MetacatException, IOException, -< MetacatInaccessibleException -< { -< Reader reader = null; -< String doctext = null; -< String schematext = null; -< try { -< doctext = IOUtil.getAsString(xmlDocument, true); -< if (schema != null) { -< schematext = IOUtil.getAsString(schema, true); -< } -< } catch (IOException ioE) { -< throw ioE; -< } -< -< //set up properties -< Properties prop = new Properties(); -< prop.put("action", "update"); -< prop.put("docid", docid); -< prop.put("doctext", doctext); -< if (schematext != null) { -< prop.put("dtdtext", schematext); -< } -< -< String response = null; -< try { -< response = sendDataForString(prop, null, null, 0); -< } catch (Exception e) { -< throw new MetacatInaccessibleException(e.getMessage()); -< } -< -< // Check for an error condition -< if (response.indexOf("") != -1) { -< if (response.indexOf("does not have permission") != -1) { -< throw new InsufficientKarmaException(response); -< } else { -< throw new MetacatException(response); -< } -< } -< -< return response; -< } -< -< /** -< * Upload a data document into the repository. -< * -< * @param docid the docid to insert the document -< * @param document a Reader for accessing the document to be uploaded -< * @return the metacat response message -< * @throws InsufficientKarmaException when the user has insufficent rights -< * for the operation -< * @throws MetacatInaccessibleException when the metacat server can not be -< * reached or does not respond -< * @throws MetacatException when the metacat server generates another error -< * @throws IOException when there is an error reading the xml document -< */ -< public String upload(String docid, File file) -< throws InsufficientKarmaException, MetacatException, IOException, -< MetacatInaccessibleException -< { -< -< URL url = new URL(metacatUrl.trim()); -< HttpMessage msg = new HttpMessage(url); -< //set up properties -< Properties arg = new Properties(); -< arg.put("action", "upload"); -< arg.put("docid", docid); -< -< Properties filenames = new Properties(); -< String filename = file.getAbsolutePath(); -< filenames.put("datafile", filename); -< -< String response = null; -< try { -< response = sendDataForString(arg, filenames, null, 0); -< } catch (Exception e) { -< throw new MetacatInaccessibleException(e.getMessage()); -< } -< -< // Check for an error condition -< if (response.indexOf("") != -1) { -< if (response.indexOf("does not have permission") != -1) { -< throw new InsufficientKarmaException(response); -< } else { -< throw new MetacatException(response); -< } -< } -< -< return response; -< } -< -< /** -< * Upload a data document into the repository. -< * -< * @param docid the docid to insert the document -< * @param document a Reader for accessing the document to be uploaded -< * @return the metacat response message -< * @throws InsufficientKarmaException when the user has insufficent rights -< * for the operation -< * @throws MetacatInaccessibleException when the metacat server can not be -< * reached or does not respond -< * @throws MetacatException when the metacat server generates another error -< * @throws IOException when there is an error reading the xml document -< */ -< -< -< public String upload(String docid, String filename, InputStream fileData, -< int size) -< throws InsufficientKarmaException, MetacatException, IOException, -< MetacatInaccessibleException { -< -< URL url = new URL(metacatUrl.trim()); -< HttpMessage msg = new HttpMessage(url); -< //set up properties -< Properties arg = new Properties(); -< arg.put("action", "upload"); -< arg.put("docid", docid); -< -< Properties filenames = new Properties(); -< filenames.put("datafile", filename); -< -< String response = null; -< try { -< response = sendDataForString(arg, filenames, fileData, size); -< } catch (Exception e) { -< throw new MetacatInaccessibleException(e.getMessage()); -< } -< -< // Check for an error condition -< if (response.indexOf("") != -1) { -< if (response.indexOf("does not have permission") != -1) { -< throw new InsufficientKarmaException(response); -< } else { -< throw new MetacatException(response); -< } -< } -< -< return response; -< } -< -< /** -< * Delete an XML document in the repository. -< * -< * @param docid the docid to delete -< * @return the metacat response message -< * @throws InsufficientKarmaException when the user has insufficent rights -< * for the operation -< * @throws MetacatInaccessibleException when the metacat server can not be -< * reached or does not respond -< * @throws MetacatException when the metacat server generates another error -< */ -< public String delete(String docid) -< throws InsufficientKarmaException, MetacatException, -< MetacatInaccessibleException -< { -< //set up properties -< Properties prop = new Properties(); -< prop.put("action", "delete"); -< prop.put("docid", docid); -< -< String response = null; -< try { -< response = sendDataForString(prop, null, null, 0); -< } catch (Exception e) { -< throw new MetacatInaccessibleException(e.getMessage()); -< } -< -< // Check for an error condition -< if (response.indexOf("") != -1) { -< if (response.indexOf("does not have permission") != -1) { -< throw new InsufficientKarmaException(response); -< } else { -< throw new MetacatException(response); -< } -< } -< return response; -< } -< -< -< /** -< * set the access on an XML document in the repository. -< * -< * @param _docid the docid of the document for which the access should be applied. -< * -< * @param _principal the document's principal -< * -< * @param _permission the access permission to be applied to the docid -< * {e.g. read,write,all} -< * -< * @param _permType the permission type to be applied to the document -< * {e.g. allow or deny} -< * -< * @param _permOrder the order that the document's permissions should be -< * processed {e.g. denyFirst or allowFirst} -< * -< * -< * @return the metacat response message -< * -< * @throws InsufficientKarmaException when the user has insufficent rights -< * for the operation -< * @throws MetacatInaccessibleException when the metacat server can not be -< * reached or does not respond -< * @throws MetacatException when the metacat server generates another error -< */ -< public String setAccess(String _docid, String _principal, String -< _permission, String _permType, -< String _permOrder ) -< throws InsufficientKarmaException, MetacatException, -< MetacatInaccessibleException -< { -< //set up properties -< Properties prop = new Properties(); -< prop.put("action", "setaccess"); -< prop.put("docid", _docid); -< prop.put("principal", _principal); -< prop.put("permission", _permission); -< prop.put("permType", _permType); -< prop.put("permOrder", _permOrder); -< -< String response = null; -< try { -< response = sendDataForString(prop, null, null, 0); -< } catch (Exception e) { -< throw new MetacatInaccessibleException(e.getMessage()); -< } -< -< // Check for an error condition -< if (response.indexOf("") != -1) { -< if (response.indexOf("does not have permission") != -1) { -< throw new InsufficientKarmaException(response); -< } else { -< throw new MetacatException(response); -< } -< } -< return response; -< } -< -< /** -< * When the MetacatFactory creates an instance it needs to set the -< * MetacatUrl to which connections should be made. -< * -< * @param metacatUrl the URL for the metacat server -< */ -< public void setMetacatUrl(String metacatUrl) -< { -< this.metacatUrl = metacatUrl; -< } -< -< /** -< * Get the session identifier for this session. This is only valid if -< * the login methods has been called successfully for this Metacat object -< * beforehand. -< * -< * @returns the sessionId as a String, or null if the session is invalid -< */ -< public String getSessionId() -< { -< return this.sessionId; -< } -< -< /** -< * Set the session identifier for this session. This identifier was -< * previously established with a call to login. To continue to use the -< * same session, set the session id before making a call to one of the -< * metacat access methods (e.g., read, query, insert, etc.). -< * -< * @param String the sessionId from a previously established session -< */ -< public void setSessionId(String sessionId) -< { -< this.sessionId = sessionId; -< } -< -< /** -< * The method will return the lasted revision in metacat server -< * for a given document id. If some error happent, this method will throw -< * a exception. -< * @param docId String the given docid you want to use. the docid it self -< * can have or haven't revision number -< * @throws MetacatException -< */ -< public int getNewestDocRevision(String docId) throws MetacatException -< { -< int rev = 0; -< //set up properties -< Properties prop = new Properties(); -< prop.put("action", "getrevisionanddoctype"); -< prop.put("docid", docId); -< -< String response = null; -< try -< { -< response = sendDataForString(prop, null, null, 0); -< String revStr = parserRevisionResponse(response); -< Integer revObj = new Integer(revStr); -< rev = revObj.intValue(); -< // Check for an error condition -< if (response.indexOf("") != -1) -< { -< throw new MetacatException(response); -< } -< -< } -< catch (Exception e) -< { -< throw new MetacatException(e.getMessage()); -< } -< return rev; -< } -< -< -< /************************************************************************ -< * PRIVATE METHODS -< ************************************************************************/ -< -< /** -< * Send a request to metacat. -< * -< * @param prop the properties to be URL encoded and sent -< * @param filename the properties to be sent to Metacat -< * in case of upload, otherwise null -< * @param fileData the inputStream for the file data to be sent to Metacat -< * in case of upload, otherwise null -< * @param size the size of the data being sent to Metacat -< * in case of upload, otherwise 0 -< */ -< synchronized private InputStream sendDataOnce(Properties args, -< Properties filename, -< InputStream fileData, -< int size) -< throws Exception -< { -< InputStream returnStream = null; -< URL url = new URL(metacatUrl); -< HttpMessage msg = new HttpMessage(url); -< msg.setCookie("JSESSIONID="+this.sessionId); -< if (filename == null){ -< returnStream = msg.sendPostData(args); -< } else if (fileData == null){ -< returnStream = msg.sendPostData(args, filename); -< } else if (size > 0) { -< returnStream = msg.sendPostData(args, filename, fileData, size); -< } else { -< throw new MetacatException("Invalid size specified for " + -< "the input stream being passed"); -< } -< return returnStream; -< } -< -< /** -< * Send a request to Metacat -< * -< * @param args the properties to be sent to Metacat -< * @param filename the properties to be sent to Metacat -< * in case of upload, otherwise null -< * @param fileData the inputStream for the file data to be sent to Metacat -< * in case of upload, otherwise null -< * @param size the size of the data being sent to Metacat -< * in case of upload, otherwise 0 -< * @return InputStream as returned by Metacat -< */ -< synchronized private InputStream sendData(Properties args, -< Properties filename, -< InputStream fileData, -< int size) -< throws Exception -< { -< InputStream returnStream = null; -< -< /* -< Note: The reason that there are three try statements all executing -< the same code is that there is a problem with the initial connection -< using the HTTPClient protocol handler. These try statements make -< sure that a connection is made because it gives each connection a -< 2nd and 3rd chance to work before throwing an error. -< THIS IS A TOTAL HACK. THIS NEEDS TO BE LOOKED INTO AFTER THE BETA1 -< RELEASE OF MORPHO!!! cwb (7/24/01) -< */ -< try { -< return sendDataOnce(args, filename, fileData, size); -< } catch (Exception e) { -< try { -< return sendDataOnce(args, filename, fileData, size); -< } catch (Exception e2) { -< try { -< return sendDataOnce(args, filename, fileData, size); -< } catch (Exception e3) { -< System.err.println( -< "Failed to send data to metacat 3 times."); -< throw e3; -< } -< } -< } -< } -< -< /** -< * Send a request to Metacat -< * -< * @param args the properties to be sent to Metacat -< * @param filename the properties to be sent to Metacat -< * in case of upload, otherwise null -< * @param fileData the inputStream for the file data to be sent to Metacat -< * in case of upload, otherwise null -< * @param size the size of the data being sent to Metacat -< * in case of upload, otherwise 0 -< * @return a string as returned by Metacat -< */ -< synchronized private String sendDataForString(Properties args, -< Properties filename, -< InputStream fileData, -< int size) -< throws Exception -< { -< String response = null; -< -< try { -< InputStreamReader returnStream = -< new InputStreamReader(sendData(args, filename, -< fileData, size)); -< StringWriter sw = new StringWriter(); -< int len; -< char[] characters = new char[512]; -< while ((len = returnStream.read(characters, 0, 512)) != -1) { -< sw.write(characters, 0, len); -< } -< returnStream.close(); -< response = sw.toString(); -< sw.close(); -< } catch (Exception e) { -< throw e; -< } -< return response; -< } -< -< /* -< * "getversionanddoctype" action will return a string from metacat server. -< * The string format is "revision;doctype"(This is bad idea, we should use xml) -< * This method will get revision string from the response string -< */ -< private String parserRevisionResponse(String response) throws Exception -< { -< String revision = null; -< if (response != null) -< { -< int firstSemiCol = response.indexOf(";"); -< revision = response.substring(0, firstSemiCol); -< } -< return revision; -< } ---- -> /** -> * Constructor to create a new instance. Protected because instances -> * should only be created by the factory MetacatFactory. -> */ -> protected MetacatClient() -> { -> this.metacatUrl = null; -> this.sessionId = null; -> } -> -> /** -> * Method used to log in to a metacat server. Implementations will need -> * to cache a cookie value to make the session persistent. Each time a -> * call is made to one of the other methods (e.g., read), the cookie will -> * need to be passed back to the metacat server along with the request. -> * -> * @param username the username of the user, like an LDAP DN -> * @param password the password for that user for authentication -> * @return the response string from metacat in XML format -> * @throws MetacatAuthException when the username/password could -> * not be authenticated -> */ -> public String login(String username, String password) -> throws MetacatAuthException, MetacatInaccessibleException -> { -> Properties prop = new Properties(); -> prop.put("action", "login"); -> prop.put("qformat", "xml"); -> if (username != null) prop.put("username", username); -> if (password != null) prop.put("password", password); -> -> String response = null; -> try { -> response = sendDataForString(prop, null, null, 0); -> } catch (Exception e) { -> throw new MetacatInaccessibleException(e); -> } -> -> if (response.indexOf("") == -1) { -> setSessionId(""); -> throw new MetacatAuthException(response); -> } else { -> int start = response.indexOf("") + 11; -> int end = response.indexOf(""); -> if ((start != -1) && (end != -1)) { -> setSessionId(response.substring(start,end)); -> } -> } -> return response; -> } -> -> /** -> * Not implemented -- use {@link MetacatGsiClient} instead. -> * @throws UnsupportedOperationException every time -> */ -> public String login(GSSCredential credential) -> throws MetacatAuthException, MetacatInaccessibleException -> { -> // be careful not to do any class-loading here, since some clients will -> // not have the JARs needed to run the GSI-enabled Metacat client. -> throw new UnsupportedOperationException -> ("Not implemented -- use MetacatGsiClient instead."); -> } -> -> /** -> * Log in over a trusted connection (usually localhost HTTP) with just -> * a username to identify the user. The server will only allow this login -> * method if it is configured to fully trust incoming connections from this -> * client. -> * -> *

    This may be used, depending on the server's configuration, with -> * a PKI Distinguished Name (DN), or with an LDAP name.

    -> */ -> public String login(String username) -> throws MetacatInaccessibleException, MetacatAuthException -> { -> return login(username, null); -> } -> -> /** -> * Method used to log out a metacat server. The Metacat server will end -> * the session when this call is invoked. -> * -> * @return the response string from metacat in XML format -> * @throws MetacatInaccessibleException when the metacat server can not be -> * reached or does not respond -> */ -> public String logout() throws MetacatInaccessibleException, MetacatException -> { -> Properties prop = new Properties(); -> prop.put("action", "logout"); -> prop.put("qformat", "xml"); -> -> String response = null; -> try { -> response = sendDataForString(prop, null, null, 0); -> } catch (Exception e) { -> throw new MetacatInaccessibleException(e); -> } -> -> if (response.indexOf("") == -1) { -> throw new MetacatException(response); -> } -> setSessionId(""); -> return response; -> } -> -> /** -> * Read an XML document from the metacat server session, accessed by docid, -> * and returned as a Reader. -> * -> * @param docid the identifier of the document to be read -> * @return a Reader for accessing the document -> * @throws InsufficientKarmaException when the user has insufficent rights -> * for the operation -> * @throws MetacatInaccessibleException when the metacat server can not be -> * reached or does not respond -> * @throws MetacatException when the metacat server generates another error -> */ -> public Reader read(String docid) throws InsufficientKarmaException, -> MetacatInaccessibleException, MetacatException -> { -> PushbackReader pbr = null; -> -> Properties prop = new Properties(); -> prop.put("action", "read"); -> prop.put("qformat", "xml"); -> prop.put("docid", docid); -> -> InputStream response = null; -> try { -> response = sendData(prop, null, null, 0); -> } catch (Exception e) { -> throw new MetacatInaccessibleException(e); -> } -> -> pbr = new PushbackReader(new InputStreamReader(response), 512); -> try { -> char[] characters = new char[512]; -> int len = pbr.read(characters, 0, 512); -> StringWriter sw = new StringWriter(); -> sw.write(characters, 0, len); -> String message = sw.toString(); -> sw.close(); -> pbr.unread(characters, 0, len); -> -> if (message.indexOf("") != -1) { -> if (message.indexOf("does not have permission") != -1) { -> throw new InsufficientKarmaException(message); -> } else { -> throw new MetacatException(message); -> } -> } -> } catch (IOException ioe) { -> throw new MetacatException( -> "MetacatClient: Error converting Reader to String: " -> + ioe.getMessage(), ioe); -> } -> -> return pbr; -> } -> -> -> /** -> * Read inline data from the metacat server session, accessed by -> * inlinedataid and returned as a Reader. -> * -> * @param inlinedataid the identifier of the data to be read -> * @return a Reader for accessing the document -> * @throws InsufficientKarmaException when the user has insufficent rights -> * for the operation -> * @throws MetacatInaccessibleException when the metacat server can not be -> * reached or does not respond -> * @throws MetacatException when the metacat server generates another error -> */ -> public Reader readInlineData(String inlinedataid) -> throws InsufficientKarmaException, -> MetacatInaccessibleException, MetacatException -> { -> PushbackReader pbr = null; -> -> Properties prop = new Properties(); -> prop.put("action", "readinlinedata"); -> prop.put("inlinedataid", inlinedataid); -> -> InputStream response = null; -> try { -> response = sendData(prop, null, null, 0); -> } catch (Exception e) { -> throw new MetacatInaccessibleException(e); -> } -> -> pbr = new PushbackReader(new InputStreamReader(response), 512); -> try { -> char[] characters = new char[512]; -> int len = pbr.read(characters, 0, 512); -> StringWriter sw = new StringWriter(); -> sw.write(characters, 0, len); -> String message = sw.toString(); -> sw.close(); -> pbr.unread(characters, 0, len); -> -> if (message.indexOf("") != -1) { -> if (message.indexOf("does not have permission") != -1) { -> throw new InsufficientKarmaException(message); -> } else { -> throw new MetacatException(message); -> } -> } -> } catch (IOException ioe) { -> throw new MetacatException( -> "MetacatClient: Error converting Reader to String: " -> + ioe.getMessage(), ioe); -> } -> -> return pbr; -> } -> -> /** -> * Query the metacat document store with the given metacat-compatible -> * query document, and return the result set as a Reader. -> * -> * @param xmlQuery a Reader for accessing the XML version of the query -> * @return a Reader for accessing the result set -> */ -> public Reader query(Reader xmlQuery) throws MetacatInaccessibleException, -> IOException -> { -> Reader reader = null; -> String query = null; -> try { -> query = IOUtil.getAsString(xmlQuery, true); -> } catch (IOException ioE) { -> throw ioE; -> } -> -> //set up properties -> Properties prop = new Properties(); -> prop.put("action", "squery"); -> prop.put("qformat", "xml"); -> prop.put("query", query); -> -> InputStream response = null; -> try { -> response = sendData(prop, null, null, 0); -> } catch (Exception e) { -> throw new MetacatInaccessibleException(e); -> } -> reader = new InputStreamReader(response); -> return reader; -> } -> -> /** -> * Insert an XML document into the repository. -> * -> * @param docid the docid to insert the document -> * @param xmlDocument a Reader for accessing the XML document to be inserted -> * @param schema a Reader for accessing the DTD or XML Schema for -> * the document -> * @return the metacat response message -> * @throws InsufficientKarmaException when the user has insufficent rights -> * for the operation -> * @throws MetacatInaccessibleException when the metacat server can not be -> * reached or does not respond -> * @throws MetacatException when the metacat server generates another error -> * @throws IOException when there is an error reading the xml document -> */ -> public String insert(String docid, Reader xmlDocument, Reader schema) -> throws InsufficientKarmaException, MetacatException, IOException, -> MetacatInaccessibleException -> { -> Reader reader = null; -> String doctext = null; -> String schematext = null; -> try { -> doctext = IOUtil.getAsString(xmlDocument, true); -> if (schema != null) { -> schematext = IOUtil.getAsString(schema, true); -> } -> } catch (IOException ioE) { -> throw ioE; -> } -> -> //set up properties -> Properties prop = new Properties(); -> prop.put("action", "insert"); -> prop.put("docid", docid); -> prop.put("doctext", doctext); -> if (schematext != null) { -> prop.put("dtdtext", schematext); -> } -> -> String response = null; -> try { -> response = sendDataForString(prop, null, null, 0); -> } catch (Exception e) { -> throw new MetacatInaccessibleException(e); -> } -> -> // Check for an error condition -> if (response.indexOf("") != -1) { -> if (response.indexOf("does not have permission") != -1) { -> throw new InsufficientKarmaException(response); -> } else { -> throw new MetacatException(response); -> } -> } -> -> return response; -> } -> -> /** -> * Update an XML document in the repository. -> * -> * @param docid the docid to update -> * @param xmlDocument a Reader for accessing the XML text to be updated -> * @param schema a Reader for accessing the DTD or XML Schema for -> * the document -> * @return the metacat response message -> * @throws InsufficientKarmaException when the user has insufficent rights -> * for the operation -> * @throws MetacatInaccessibleException when the metacat server can not be -> * reached or does not respond -> * @throws MetacatException when the metacat server generates another error -> * @throws IOException when there is an error reading the xml document -> */ -> public String update(String docid, Reader xmlDocument, Reader schema) -> throws InsufficientKarmaException, MetacatException, IOException, -> MetacatInaccessibleException -> { -> Reader reader = null; -> String doctext = null; -> String schematext = null; -> try { -> doctext = IOUtil.getAsString(xmlDocument, true); -> if (schema != null) { -> schematext = IOUtil.getAsString(schema, true); -> } -> } catch (IOException ioE) { -> throw ioE; -> } -> -> //set up properties -> Properties prop = new Properties(); -> prop.put("action", "update"); -> prop.put("docid", docid); -> prop.put("doctext", doctext); -> if (schematext != null) { -> prop.put("dtdtext", schematext); -> } -> -> String response = null; -> try { -> response = sendDataForString(prop, null, null, 0); -> } catch (Exception e) { -> throw new MetacatInaccessibleException(e); -> } -> -> // Check for an error condition -> if (response.indexOf("") != -1) { -> if (response.indexOf("does not have permission") != -1) { -> throw new InsufficientKarmaException(response); -> } else { -> throw new MetacatException(response); -> } -> } -> -> return response; -> } -> -> /** -> * Upload a data document into the repository. -> * -> * @param docid the docid to insert the document -> * @param document a Reader for accessing the document to be uploaded -> * @return the metacat response message -> * @throws InsufficientKarmaException when the user has insufficent rights -> * for the operation -> * @throws MetacatInaccessibleException when the metacat server can not be -> * reached or does not respond -> * @throws MetacatException when the metacat server generates another error -> * @throws IOException when there is an error reading the xml document -> */ -> public String upload(String docid, File file) -> throws InsufficientKarmaException, MetacatException, IOException, -> MetacatInaccessibleException -> { -> -> //set up properties -> Properties arg = new Properties(); -> arg.put("action", "upload"); -> arg.put("docid", docid); -> -> Properties filenames = new Properties(); -> String filename = file.getAbsolutePath(); -> filenames.put("datafile", filename); -> -> String response = null; -> try { -> response = sendDataForString(arg, filenames, null, 0); -> } catch (Exception e) { -> throw new MetacatInaccessibleException(e); -> } -> -> // Check for an error condition -> if (response.indexOf("") != -1) { -> if (response.indexOf("does not have permission") != -1) { -> throw new InsufficientKarmaException(response); -> } else { -> throw new MetacatException(response); -> } -> } -> -> return response; -> } -> -> /** -> * Upload a data document into the repository. -> * -> * @param docid the docid to insert the document -> * @param document a Reader for accessing the document to be uploaded -> * @return the metacat response message -> * @throws InsufficientKarmaException when the user has insufficent rights -> * for the operation -> * @throws MetacatInaccessibleException when the metacat server can not be -> * reached or does not respond -> * @throws MetacatException when the metacat server generates another error -> * @throws IOException when there is an error reading the xml document -> */ -> -> -> public String upload(String docid, String filename, InputStream fileData, -> int size) -> throws InsufficientKarmaException, MetacatException, IOException, -> MetacatInaccessibleException { -> -> //set up properties -> Properties arg = new Properties(); -> arg.put("action", "upload"); -> arg.put("docid", docid); -> -> Properties filenames = new Properties(); -> filenames.put("datafile", filename); -> -> String response; -> try { -> response = sendDataForString(arg, filenames, fileData, size); -> } catch (Exception e) { -> throw new MetacatInaccessibleException(e); -> } -> -> // Check for an error condition -> if (response.indexOf("") != -1) { -> if (response.indexOf("does not have permission") != -1) { -> throw new InsufficientKarmaException(response); -> } else { -> throw new MetacatException(response); -> } -> } -> -> return response; -> } -> -> /** -> * Delete an XML document in the repository. -> * -> * @param docid the docid to delete -> * @return the metacat response message -> * @throws InsufficientKarmaException when the user has insufficent rights -> * for the operation -> * @throws MetacatInaccessibleException when the metacat server can not be -> * reached or does not respond -> * @throws MetacatException when the metacat server generates another error -> */ -> public String delete(String docid) -> throws InsufficientKarmaException, MetacatException, -> MetacatInaccessibleException -> { -> //set up properties -> Properties prop = new Properties(); -> prop.put("action", "delete"); -> prop.put("docid", docid); -> -> String response = null; -> try { -> response = sendDataForString(prop, null, null, 0); -> } catch (Exception e) { -> throw new MetacatInaccessibleException(e); -> } -> -> // Check for an error condition -> if (response.indexOf("") != -1) { -> if (response.indexOf("does not have permission") != -1) { -> throw new InsufficientKarmaException(response); -> } else { -> throw new MetacatException(response); -> } -> } -> return response; -> } -> -> -> /** -> * set the access on an XML document in the repository. -> * -> * @param _docid the docid of the document for which the access should be applied. -> * -> * @param _principal the document's principal -> * -> * @param _permission the access permission to be applied to the docid -> * {e.g. read,write,all} -> * -> * @param _permType the permission type to be applied to the document -> * {e.g. allow or deny} -> * -> * @param _permOrder the order that the document's permissions should be -> * processed {e.g. denyFirst or allowFirst} -> * -> * -> * @return the metacat response message -> * -> * @throws InsufficientKarmaException when the user has insufficent rights -> * for the operation -> * @throws MetacatInaccessibleException when the metacat server can not be -> * reached or does not respond -> * @throws MetacatException when the metacat server generates another error -> */ -> public String setAccess(String _docid, String _principal, String -> _permission, String _permType, -> String _permOrder ) -> throws InsufficientKarmaException, MetacatException, -> MetacatInaccessibleException -> { -> //set up properties -> Properties prop = new Properties(); -> prop.put("action", "setaccess"); -> prop.put("docid", _docid); -> prop.put("principal", _principal); -> prop.put("permission", _permission); -> prop.put("permType", _permType); -> prop.put("permOrder", _permOrder); -> -> String response = null; -> try { -> response = sendDataForString(prop, null, null, 0); -> } catch (Exception e) { -> throw new MetacatInaccessibleException(e); -> } -> -> // Check for an error condition -> if (response.indexOf("") != -1) { -> if (response.indexOf("does not have permission") != -1) { -> throw new InsufficientKarmaException(response); -> } else { -> throw new MetacatException(response); -> } -> } -> return response; -> } -> -> /** -> * When the MetacatFactory creates an instance it needs to set the -> * MetacatUrl to which connections should be made. -> * -> * @param metacatUrl the URL for the metacat server -> */ -> public void setMetacatUrl(String metacatUrl) -> { -> this.metacatUrl = metacatUrl; -> } -> -> /** -> * The value set via {@link #setMetacatUrl(String)}. -> */ -> public String getMetacatUrl() -> { -> return metacatUrl; -> } -> -> /** -> * Get the session identifier for this session. This is only valid if -> * the login methods has been called successfully for this Metacat object -> * beforehand. -> * -> * @return the sessionId as a String, or null if the session is invalid -> */ -> public String getSessionId() -> { -> return this.sessionId; -> } -> -> /** -> * Set the session identifier for this session. This identifier was -> * previously established with a call to login. To continue to use the -> * same session, set the session id before making a call to one of the -> * metacat access methods (e.g., read, query, insert, etc.). -> * -> * @param sessionId the sessionId from a previously established session -> */ -> public void setSessionId(String sessionId) -> { -> this.sessionId = sessionId; -> } -> -> /** -> * The method will return the lasted revision in metacat server -> * for a given document id. If some error happent, this method will throw -> * a exception. -> * @param docId String the given docid you want to use. the docid it self -> * can have or haven't revision number -> * @throws MetacatException -> */ -> public int getNewestDocRevision(String docId) throws MetacatException -> { -> int rev = 0; -> //set up properties -> Properties prop = new Properties(); -> prop.put("action", "getrevisionanddoctype"); -> prop.put("docid", docId); -> -> String response = null; -> try -> { -> response = sendDataForString(prop, null, null, 0); -> String revStr = parserRevisionResponse(response); -> Integer revObj = new Integer(revStr); -> rev = revObj.intValue(); -> // Check for an error condition -> if (response.indexOf("") != -1) -> { -> throw new MetacatException(response); -> } -> -> } -> catch (Exception e) -> { -> throw new MetacatException(e); -> } -> return rev; -> } -> -> -> /************************************************************************ -> * PRIVATE METHODS -> ************************************************************************/ -> -> /** -> * Send a request to metacat. -> * -> * @param args the properties to be URL encoded and sent -> * @param filename the properties to be sent to Metacat -> * in case of upload, otherwise null -> * @param fileData the inputStream for the file data to be sent to Metacat -> * in case of upload, otherwise null -> * @param size the size of the data being sent to Metacat -> * in case of upload, otherwise 0 -> */ -> synchronized protected InputStream sendDataOnce(Properties args, -> Properties filename, -> InputStream fileData, -> int size) -> throws Exception -> { -> HttpMessage msg = createHttpMessage(); -> msg.setCookie("JSESSIONID="+this.sessionId); -> return xmit(msg, args, filename, fileData, size); -> } -> -> /** Create an HttpMessage that can send messages to the server. -> * Designed to be overrideable in case a subclass connects to a server -> * differently. */ -> protected HttpMessage createHttpMessage() -> throws IOException, MetacatInaccessibleException, MetacatAuthException -> { -> URL url = new URL(metacatUrl.trim()); -> return new HttpMessage(url); -> } -> -> /** Helper function to {@link #sendDataOnce}. */ -> protected static InputStream xmit -> (HttpMessage msg, Properties args, Properties filename, -> InputStream fileData, int size) -> throws MetacatException, IOException -> { -> if (filename == null){ -> return msg.sendPostData(args); -> } else if (fileData == null){ -> return msg.sendPostData(args, filename); -> } else if (size > 0) { -> return msg.sendPostData(args, filename, fileData, size); -> } else { -> throw new MetacatException("Invalid size specified for " + -> "the input stream being passed"); -> } -> } -> -> /** -> * Send a request to Metacat -> * -> * @param args the properties to be sent to Metacat -> * @param filename the properties to be sent to Metacat -> * in case of upload, otherwise null -> * @param fileData the inputStream for the file data to be sent to Metacat -> * in case of upload, otherwise null -> * @param size the size of the data being sent to Metacat -> * in case of upload, otherwise 0 -> * @return InputStream as returned by Metacat -> */ -> synchronized private InputStream sendData(Properties args, -> Properties filename, -> InputStream fileData, -> int size) -> throws Exception -> { -> InputStream returnStream = null; -> -> /* -> Note: The reason that there are three try statements all executing -> the same code is that there is a problem with the initial connection -> using the HTTPClient protocol handler. These try statements make -> sure that a connection is made because it gives each connection a -> 2nd and 3rd chance to work before throwing an error. -> THIS IS A TOTAL HACK. THIS NEEDS TO BE LOOKED INTO AFTER THE BETA1 -> RELEASE OF MORPHO!!! cwb (7/24/01) -> */ -> try { -> return sendDataOnce(args, filename, fileData, size); -> } catch (Exception e) { -> try { -> return sendDataOnce(args, filename, fileData, size); -> } catch (Exception e2) { -> try { -> return sendDataOnce(args, filename, fileData, size); -> } catch (Exception e3) { -> System.err.println( -> "Failed to send data to metacat 3 times."); -> throw e3; -> } -> } -> } -> } -> -> /** -> * Send a request to Metacat -> * -> * @param args the properties to be sent to Metacat -> * @param filename the properties to be sent to Metacat -> * in case of upload, otherwise null -> * @param fileData the inputStream for the file data to be sent to Metacat -> * in case of upload, otherwise null -> * @param size the size of the data being sent to Metacat -> * in case of upload, otherwise 0 -> * @return a string as returned by Metacat -> */ -> synchronized protected String sendDataForString(Properties args, -> Properties filename, -> InputStream fileData, -> int size) -> throws Exception -> { -> InputStreamReader returnStream = -> new InputStreamReader(sendData(args, filename, -> fileData, size)); -> StringWriter sw = new StringWriter(); -> int len; -> char[] characters = new char[512]; -> while ((len = returnStream.read(characters, 0, 512)) != -1) { -> sw.write(characters, 0, len); -> } -> returnStream.close(); -> String response = sw.toString(); -> sw.close(); -> return response; -> } -> -> /* -> * "getversionanddoctype" action will return a string from metacat server. -> * The string format is "revision;doctype"(This is bad idea, we should use xml) -> * This method will get revision string from the response string -> */ -> private String parserRevisionResponse(String response) throws Exception -> { -> String revision = null; -> if (response != null) -> { -> int firstSemiCol = response.indexOf(";"); -> revision = response.substring(0, firstSemiCol); -> } -> return revision; -> } -Index: src/edu/ucsb/nceas/metacat/client/MetacatException.java -=================================================================== -RCS file: /cvs/metacat/src/edu/ucsb/nceas/metacat/client/MetacatException.java,v -retrieving revision 1.1 -diff -r1.1 MetacatException.java -39a40,47 -> -> public MetacatException(Throwable cause) { -> super(cause); -> } -> -> public MetacatException(String message, Throwable cause) { -> super(message, cause); -> } -Index: src/edu/ucsb/nceas/metacat/client/MetacatFactory.java -=================================================================== -RCS file: /cvs/metacat/src/edu/ucsb/nceas/metacat/client/MetacatFactory.java,v -retrieving revision 1.1 -diff -r1.1 MetacatFactory.java -27c27,31 -< import java.io.Reader; ---- -> import java.net.URL; -> import java.net.MalformedURLException; -> import java.util.Map; -> import java.util.HashMap; -> import java.util.Collections; -35,36c39,84 -< private static final String metacatClientClass = -< "edu.ucsb.nceas.metacat.client.MetacatClient"; ---- -> /** Register Metacat client classes by protocol. */ -> private static final Map PROTOCOL_CLIENT_CLASS_MAP; -> static { -> Map protoMap = new HashMap(); -> protoMap.put("http", "edu.ucsb.nceas.metacat.client.MetacatClient"); -> // protoMap.put("https", "edu.ucsb.nceas.metacat.client.MetacatClient"); -> protoMap.put("https", "edu.ucsb.nceas.metacat.client.gsi.MetacatGsiClient"); -> // httpg requires a special class that requires GSI libraries -> protoMap.put("httpg", "edu.ucsb.nceas.metacat.client.gsi.MetacatGsiClient"); -> PROTOCOL_CLIENT_CLASS_MAP = Collections.unmodifiableMap(protoMap); -> } -> -> /** -> * Create a new instance of a Metacat object of raccessing a server. -> * -> * @param metacatUrl the url location of the metacat server -> * @throws MetacatInaccessibleException when the metacat server can not -> * be reached -> */ -> public static Metacat createMetacatConnection(String metacatUrl) -> throws MetacatInaccessibleException -> { -> Metacat m; -> try { -> URL url = new URL(metacatUrl); -> String clientClass = (String) -> PROTOCOL_CLIENT_CLASS_MAP.get(url.getProtocol().toLowerCase()); -> if (clientClass == null) -> clientClass = (String) PROTOCOL_CLIENT_CLASS_MAP.get("http"); -> Class c = Class.forName(clientClass); -> m = (Metacat)c.newInstance(); -> } catch (InstantiationException e) { -> throw new MetacatInaccessibleException(e); -> } catch (IllegalAccessException e) { -> throw new MetacatInaccessibleException(e); -> } catch (ClassNotFoundException e) { -> throw new MetacatInaccessibleException -> ("Unable to instantiate metacat client for server URL \"" -> + metacatUrl + "\".", e); -> } catch (NoClassDefFoundError e) { -> throw new MetacatInaccessibleException -> ("Unable to instantiate metacat client for server URL \"" -> + metacatUrl + "\".", e); -> } catch (MalformedURLException e) { -> throw new MetacatInaccessibleException(e); -> } -38,58c86 -< /** -< * Create a new instance of a Metacat object of raccessing a server. -< * -< * @param metacatUrl the url location of the metacat server -< * @throws MetacatInaccessibleException when the metacat server can not -< * be reached -< */ -< public static Metacat createMetacatConnection(String metacatUrl) -< throws MetacatInaccessibleException -< { -< Metacat m = null; -< try { -< Class c = Class.forName(metacatClientClass); -< m = (Metacat)c.newInstance(); -< } catch (InstantiationException e) { -< throw new MetacatInaccessibleException(e.getMessage()); -< } catch (IllegalAccessException e) { -< throw new MetacatInaccessibleException(e.getMessage()); -< } catch (ClassNotFoundException e) { -< throw new MetacatInaccessibleException(e.getMessage()); -< } ---- -> m.setMetacatUrl(metacatUrl); -60,63c88,89 -< m.setMetacatUrl(metacatUrl); -< -< return m; -< } ---- -> return m; -> } -Index: src/edu/ucsb/nceas/metacat/client/MetacatInaccessibleException.java -=================================================================== -RCS file: /cvs/metacat/src/edu/ucsb/nceas/metacat/client/MetacatInaccessibleException.java,v -retrieving revision 1.1 -diff -r1.1 MetacatInaccessibleException.java -40a41,48 -> -> public MetacatInaccessibleException(Throwable cause) { -> super(cause); -> } -> -> public MetacatInaccessibleException(String message, Throwable cause) { -> super(message, cause); -> } -Index: src/edu/ucsb/nceas/metacat/harvesterClient/HarvesterRegistration.java -=================================================================== -RCS file: /cvs/metacat/src/edu/ucsb/nceas/metacat/harvesterClient/HarvesterRegistration.java,v -retrieving revision 1.13 -diff -r1.13 HarvesterRegistration.java -28a29,30 -> import edu.ucsb.nceas.metacat.AuthInfo; -> -362c364 -< String ldapDN; ---- -> String ldapDN; -379,380c381,383 -< ldapDN = (String) httpSession.getAttribute("username"); -< ldapPwd = (String) httpSession.getAttribute("password"); ---- -> AuthInfo auth = (AuthInfo) httpSession.getAttribute("auth"); -> ldapDN = auth.getUsername(); -> ldapPwd = auth.getPassword(); -531,532c534,536 -< ldapDN = (String) httpSession.getAttribute("username"); -< ldapPwd = (String) httpSession.getAttribute("password"); ---- -> AuthInfo auth = (AuthInfo) httpSession.getAttribute("auth"); -> ldapDN = auth.getUsername(); -> ldapPwd = auth.getPassword(); -Index: src/edu/ucsb/nceas/metacat/harvesterClient/HarvesterRegistrationLogin.java -=================================================================== -RCS file: /cvs/metacat/src/edu/ucsb/nceas/metacat/harvesterClient/HarvesterRegistrationLogin.java,v -retrieving revision 1.7 -diff -r1.7 HarvesterRegistrationLogin.java -33a34 -> import edu.ucsb.nceas.metacat.AuthInfo; -42c43 -< final String LDAP_DOMAIN = ",dc=ecoinformatics,dc=org"; ---- -> final String LDAP_DOMAIN = ",dc=ecoinformatics,dc=org"; -44,129c45,130 -< /** -< * Handle "GET" method requests from HTTP clients -< * -< * @param req The request -< * @param res The response -< * @throws ServletException, java.io.IOException -< */ -< public void doGet(HttpServletRequest req, HttpServletResponse res) -< throws ServletException, java.io.IOException { -< handleGetOrPost(req, res); -< } -< -< -< /** -< * Handle "POST" method requests from HTTP clients -< * -< * @param req The request -< * @param res The response -< * @throws ServletException, java.io.IOException -< */ -< public void doPost(HttpServletRequest req, HttpServletResponse res) -< throws ServletException, java.io.IOException { -< handleGetOrPost(req, res); -< } -< -< -< /** -< * Handle "GET" or "POST" method requests from HTTP clients -< * -< * @param req The request -< * @param res The response -< * @throws ServletException, java.io.IOException -< */ -< private void handleGetOrPost(HttpServletRequest req, -< HttpServletResponse res) -< throws ServletException, java.io.IOException { -< AuthSession authSession; -< String authSessionMessage; -< HttpSession httpSession; -< boolean isValid; -< String o = req.getParameter("o"); -< String organization; -< String passwd = req.getParameter("passwd"); -< PrintWriter out = res.getWriter(); -< String uid = req.getParameter("uid"); -< String user; -< -< if ((uid == null) || (uid.equals(""))) { -< out.println("Invalid login: no Username specified."); -< return; -< } -< else if ((o == null) || (o.equals(""))) { -< out.println("Invalid login: no Organization selected."); -< return; -< } -< else if ((passwd == null) || (passwd.equals(""))) { -< out.println("Invalid login: no Password specified."); -< return; -< } -< else { -< user = "uid=" + uid + ",o=" + o + LDAP_DOMAIN; -< } -< -< res.setContentType("text/plain"); -< -< try { -< authSession = new AuthSession(); -< isValid = authSession.authenticate(req, user, passwd); -< authSessionMessage = authSession.getMessage(); -< System.out.println("authSession.authenticate(): "+authSessionMessage); -< out.println("authSession.authenticate(): " + authSessionMessage); -< -< if (isValid) { -< httpSession = req.getSession(true); -< httpSession.setAttribute("username", user); -< httpSession.setAttribute("password", passwd); -< res.sendRedirect("harvesterRegistration"); -< } -< else { -< out.println("Invalid login"); -< } -< } -< catch (Exception e) { -< System.out.println("Error in AuthSession()" + e.getMessage()); -< } -< } ---- -> /** -> * Handle "GET" method requests from HTTP clients -> * -> * @param req The request -> * @param res The response -> * @throws ServletException, java.io.IOException -> */ -> public void doGet(HttpServletRequest req, HttpServletResponse res) -> throws ServletException, java.io.IOException { -> handleGetOrPost(req, res); -> } -> -> -> /** -> * Handle "POST" method requests from HTTP clients -> * -> * @param req The request -> * @param res The response -> * @throws ServletException, java.io.IOException -> */ -> public void doPost(HttpServletRequest req, HttpServletResponse res) -> throws ServletException, java.io.IOException { -> handleGetOrPost(req, res); -> } -> -> -> /** -> * Handle "GET" or "POST" method requests from HTTP clients -> * -> * @param req The request -> * @param res The response -> * @throws ServletException, java.io.IOException -> */ -> private void handleGetOrPost(HttpServletRequest req, -> HttpServletResponse res) -> throws ServletException, java.io.IOException { -> AuthSession authSession; -> String authSessionMessage; -> HttpSession httpSession; -> boolean isValid; -> String o = req.getParameter("o"); -> String organization; -> String passwd = req.getParameter("passwd"); -> PrintWriter out = res.getWriter(); -> String uid = req.getParameter("uid"); -> String user; -> -> if ((uid == null) || (uid.equals(""))) { -> out.println("Invalid login: no Username specified."); -> return; -> } -> else if ((o == null) || (o.equals(""))) { -> out.println("Invalid login: no Organization selected."); -> return; -> } -> else if ((passwd == null) || (passwd.equals(""))) { -> out.println("Invalid login: no Password specified."); -> return; -> } -> else { -> user = "uid=" + uid + ",o=" + o + LDAP_DOMAIN; -> } -> -> res.setContentType("text/plain"); -> -> try { -> authSession = new AuthSession(); -> AuthInfo auth = new AuthInfo(user, passwd); -> isValid = authSession.authenticate(req, auth); -> authSessionMessage = authSession.getMessage(); -> System.out.println("authSession.authenticate(): "+authSessionMessage); -> out.println("authSession.authenticate(): " + authSessionMessage); -> -> if (isValid) { -> httpSession = req.getSession(true); -> httpSession.setAttribute("auth", auth); -> res.sendRedirect("harvesterRegistration"); -> } -> else { -> out.println("Invalid login"); -> } -> } -> catch (Exception e) { -> System.out.println("Error in AuthSession()" + e.getMessage()); -> } -> } -Index: src/edu/ucsb/nceas/metacat/harvesterClient/LoginServlet.java -=================================================================== -RCS file: /cvs/metacat/src/edu/ucsb/nceas/metacat/harvesterClient/LoginServlet.java,v -retrieving revision 1.6 -diff -r1.6 LoginServlet.java -38a39 -> import edu.ucsb.nceas.metacat.AuthInfo; -46,47c47,48 -< // Close all connections -< System.out.println("Destroying LoginServlet"); ---- -> // Close all connections -> System.out.println("Destroying LoginServlet"); -58,60c59,61 -< throws ServletException, java.io.IOException { -< // Process the data and send back the response -< handleGetOrPost(request, response); ---- -> throws ServletException, java.io.IOException { -> // Process the data and send back the response -> handleGetOrPost(request, response); -71,73c72,74 -< throws ServletException, java.io.IOException { -< // Process the data and send back the response -< handleGetOrPost(request, response); ---- -> throws ServletException, java.io.IOException { -> // Process the data and send back the response -> handleGetOrPost(request, response); -84,115c85,116 -< HttpServletResponse response) -< throws ServletException, java.io.IOException { -< AuthSession authSession = null; -< HttpSession httpSession; -< boolean isValid; -< PrintWriter out = response.getWriter(); -< String passwd = request.getParameter("passwd"); -< String user = request.getParameter("user"); -< -< response.setContentType("text/plain"); -< -< try { -< authSession = new AuthSession(); -< } -< catch (Exception e) { -< out.println("Error creating AuthSession: " + e.getMessage()); -< return; -< } -< -< isValid = authSession.authenticate(request, user, passwd); -< -< if (isValid) { -< System.out.println(authSession.getMessage()); -< httpSession = request.getSession(true); -< httpSession.setAttribute("username", user); -< httpSession.setAttribute("password", passwd); -< response.sendRedirect("../style/skins/dev/harvesterUpload.html"); -< } -< else { -< out.println("Error authenticating Metacat login: " + -< authSession.getMessage()); -< } ---- -> HttpServletResponse response) -> throws ServletException, java.io.IOException { -> AuthSession authSession = null; -> HttpSession httpSession; -> boolean isValid; -> PrintWriter out = response.getWriter(); -> String passwd = request.getParameter("passwd"); -> String user = request.getParameter("user"); -> AuthInfo auth = new AuthInfo(user, passwd); -> -> response.setContentType("text/plain"); -> -> try { -> authSession = new AuthSession(); -> } -> catch (Exception e) { -> out.println("Error creating AuthSession: " + e.getMessage()); -> return; -> } -> -> isValid = authSession.authenticate(request, auth); -> -> if (isValid) { -> System.out.println(authSession.getMessage()); -> httpSession = request.getSession(true); -> httpSession.setAttribute("auth", auth); -> response.sendRedirect("../style/skins/dev/harvesterUpload.html"); -> } -> else { -> out.println("Error authenticating Metacat login: " + -> authSession.getMessage()); -> } -Index: src/edu/ucsb/nceas/metacat/harvesterClient/MetUpload.java -=================================================================== -RCS file: /cvs/metacat/src/edu/ucsb/nceas/metacat/harvesterClient/MetUpload.java,v -retrieving revision 1.8 -diff -r1.8 MetUpload.java -44a45 -> import edu.ucsb.nceas.metacat.AuthInfo; -84c85 -< String password = (String) sess.getAttribute("password"); ---- -> AuthInfo auth = (AuthInfo) sess.getAttribute("auth"); -87,88c88 -< String username = (String) sess.getAttribute("username"); -< ---- -> -124c124 -< upload(out, docid, sr, username, password); ---- -> upload(out, docid, sr, auth); -127c127 -< delete(out, docid, username, password); ---- -> delete(out, docid, auth); -137,138c137 -< * @param username the Metacat username -< * @param password the Metacat password ---- -> * @param auth the Metacat username and password -142,143c141 -< String username, -< String password ---- -> AuthInfo auth -155c153 -< metacat.login(username, password); ---- -> metacat.login(auth.getUsername(), auth.getPassword()); -220,221c218 -< * @param username the Metacat username -< * @param password the Metacat password ---- -> * @param auth the Metacat username and password -226,227c223 -< String username, -< String password ---- -> AuthInfo auth -247c243 -< metacat.login(username, password); ---- -> metacat.login(auth.getUsername(), auth.getPassword()); diff --git a/lib/certificateAuthenCode/bbaker_diff_utilities.txt b/lib/certificateAuthenCode/bbaker_diff_utilities.txt deleted file mode 100644 index b7b322f6f..000000000 --- a/lib/certificateAuthenCode/bbaker_diff_utilities.txt +++ /dev/null @@ -1,138 +0,0 @@ -Index: build.xml -=================================================================== -RCS file: /cvs/utilities/build.xml,v -retrieving revision 1.8 -diff -w -r1.8 build.xml -66a67,68 -> -> -69c71 -< value="${xercesjar}:${log4jjar}:${httpjar}" /> ---- -> value="${xercesjar}:${log4jjar}:${httpjar}:${jglobusjar}:${jgssjar}:${xalanjar}" /> -97a100 -> source="1.4" target="1.4" -164a168 -> source="1.4" target="1.4" -Index: src/java/edu/ucsb/nceas/utilities/HttpMessage.java -=================================================================== -RCS file: /cvs/utilities/src/java/edu/ucsb/nceas/utilities/HttpMessage.java,v -retrieving revision 1.3 -diff -w -r1.3 HttpMessage.java -27,30d26 -< import java.io.*; -< import java.net.*; -< import java.util.*; -< -32a29,36 -> import java.io.*; -> import java.net.HttpURLConnection; -> import java.net.URL; -> import java.net.URLConnection; -> import java.net.URLEncoder; -> import java.util.Enumeration; -> import java.util.Properties; -> -35,39c39,42 -< private URL servlet = null; -< private String argString = null; -< private static String cookie = null; -< private OutputStream out = null; -< private URLConnection con = null; ---- -> protected URL servlet = null; -> protected String cookie = null; -> protected OutputStream out = null; -> protected URLConnection con = null; -61c64 -< argString = "";//default ---- -> String argString = ""; -79c82 -< private void openPostConnection() throws IOException ---- -> protected void openPostConnection() throws IOException -153c156 -< ((HttpURLConnection)con).setRequestProperty("Content-Type", ctype); ---- -> con.setRequestProperty("Content-Type", ctype); -155,156c158 -< ((HttpURLConnection)con).setRequestProperty("Content-Length", -< new Long(contentLength).toString()); ---- -> con.setRequestProperty("Content-Length", Long.toString(contentLength)); -159c161 -< out = con.getOutputStream(); ---- -> out = getConOutputStream(); -214c216 -< ((HttpURLConnection)con).setRequestProperty("Content-Type", ctype); ---- -> con.setRequestProperty("Content-Type", ctype); -216,217c218 -< ((HttpURLConnection)con).setRequestProperty("Content-Length", -< new Long(contentLength).toString()); ---- -> con.setRequestProperty("Content-Length", Long.toString(contentLength)); -220c221 -< out = con.getOutputStream(); ---- -> out = getConOutputStream(); -227a229,256 -> /** If true, ignore all flush() calls during POST connections -> * (that is, during sendPostData calls) until the connection is -> * closed. Useful because flush() calls on a GSS SSL stream close the -> * stream. */ -> protected boolean ignoreOutputStreamFlushes = false; -> -> /** If ignoreOutputStreamFlushes is true, wrap o in a -> * stream that simply ignores all flush()es until it is closed. -> * No effect if ignoreOutputStreamFlushes is false. */ -> private OutputStream wrapFlushes(OutputStream o) { -> if (!ignoreOutputStreamFlushes) return o; -> else return new FilterOutputStream(o) { -> public void flush() {} // ignore flushes -> public void close() throws IOException { -> //noinspection EmptyCatchBlock -> try { super.flush(); } // but make sure they happen on close -> catch (IOException ignored) {} -> super.close(); -> } -> }; -> } -> -> /** Call this rather than calling con.getOutputStream() directly, -> * to properly wrap a GSI SSL output stream. */ -> protected OutputStream getConOutputStream() throws IOException { -> return wrapFlushes(con.getOutputStream()); -> } -> -240c269 -< out = new DataOutputStream(con.getOutputStream()); ---- -> out = new DataOutputStream(getConOutputStream()); -272c301 -< private InputStream closePostConnection() throws IOException ---- -> protected InputStream closePostConnection() throws IOException -297c326 -< return sendPostMessage(null); ---- -> return sendPostData(null); -319c348 -< private String toEncodedString(Properties args) ---- -> protected static String toEncodedString(Properties args) -327c356,357 -< buf.append(URLEncoder.encode(name) + "=" + URLEncoder.encode(value)); ---- -> buf.append(URLEncoder.encode(name)).append("=") -> .append(URLEncoder.encode(value)); -337c367 -< public static String getCookie() ---- -> public String getCookie() -345c375 -< public static void setCookie(String newCookie) ---- -> public void setCookie(String newCookie) diff --git a/lib/certificateAuthenCode/metacat_additions.tar.gz b/lib/certificateAuthenCode/metacat_additions.tar.gz deleted file mode 100644 index 451d5b242..000000000 Binary files a/lib/certificateAuthenCode/metacat_additions.tar.gz and /dev/null differ diff --git a/workflowscheduler.build.xml b/workflowscheduler.build.xml deleted file mode 100644 index 2fea223c7..000000000 --- a/workflowscheduler.build.xml +++ /dev/null @@ -1,431 +0,0 @@ - - - - - - - - - - - - - - - *********** set jsdk to ${jsdk} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Enter CVS password: - - - - - - - - - - Dev install completed at ${NOW} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -