? 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
>       <filter token="auth-method" value="${auth-method}"/>
>       <filter token="auth-delegate" value="${auth-delegate}"/>
>       <filter token="auth-delegation-allowed" value="${auth-delegation-allowed}"/>
>       <filter token="auth-precedence" value="${auth-precedence}"/>
>       <filter token="auth-trust-localhost" value="${auth-trust-localhost}"/>
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
>   <style type="text/css" media="screen">
>   <!--
>     .tooltip { border-bottom:1px solid #00f }
>     .tooltip:hover { background: #fc9 }
>     .sample { border:1px solid black; padding:0.3em; }
>     .existing { color:#666 }
>   -->
>   </style>
618a627,917
> 
> <table class="tabledefault" width="100%">
> <td class="tablehead" colspan="2">
>   <p><a name="gsi"></a>GSI (Grid Security Infrastructure) Authentication</a></p>
> </td>
> <tr>
> <td>
>   <p class="header">Overview</p>
> 
>   <p>
>     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:
>   </p>
> 
>   <ul>
>     <li>
>       Use of security credentials enables sign-on with other grid
>       services.
>     </li>
>     <li>
>       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.
>     </li>
>   </ul>
> 
> 
>   <p class="header">Grid Security Setup</p> 
> 
>   <ol>
>     <li>
>       <p>If you don't have any Grid infrastructure available already,
>       you can <a
>       href="http://grid.ncsa.uiuc.edu/myproxy/fromscratch.html">follow
>       these instructions</a> to get started from scratch.</p>
>     </li>
> 
>     <li>
>       <p>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.</p>
>     </li>
>   </ol>
> 
>   <p class="header">Tomcat Configuration</p> 
> 
>   <ol>
>     <li>
>       <a name="tomcat_jars"></a>
>       <p>Add JARs to Tomcat's <code>$CATALINA_HOME/common/lib</code>
>       directory.  You can find them in the Metacat distribution in
>       <code>metacat/lib/gsi</code>:</p>
> 
>       <blockquote>
>         <code>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</code>
>       </blockquote>
> 
>       <p>Note that <code>cog-jglobus-ncsa.jar</code> is a modified
>       version of <code>cog-jglobus.jar</code> which comes with the <a
>       href="http://www.globus.org/toolkit/">Globus Toolkit</a>.  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.</p>
> 
>     </li>
> 
>     <li>
>       <p>Modify Tomcat's <code>server.xml</code> to listen for
>       HTTPS+GSI.  Note that you can use any available port for this
>       connector; this example uses 8443.</p>
> 
>       <p>Host credentials: The HTTPS connection will require host
>       credentials for the Metacat server; the example below assumes
>       that the host credentials are in
>       <code>/etc/grid-security</code>, which is the default location
>       for a <a href="http://www.globus.org/toolkit/">Globus
>       toolkit</a> installation.</p>
> 
>       <p>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
>       (<code>cacertdir</code>, below).  The filenames will be
>       something like <code>4a6cd8b1.0</code> and
>       <code>4a6cd8b1.signing_policy</code>.</p>
> 
>       <ul>
> 
>         <li>
>           <p>Add an <code>HTTPSConnector</code>, inside the
>           <code>&lt;Service name="Catalina"&gt;</code> section, near
>           the SSL HTTP/1.1 connector definition, which is commented
>           out by default:</p>
> 
> <pre class="sample">
> <span class="existing">&lt;!-- Define a SSL HTTP/1.1 Connector on port 8443 --&gt;
> &lt;!--
> &lt;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" /&gt;
> --&gt;</span>
> 
> &lt;!-- Define an HTTPS+GSI (HTTPS with GSI credentials) Connector on port 8443 --&gt;
> &lt;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"/&gt;
> </pre>
>         </li>
>         <li>
>           <p>Add an <code>HTTPSValve</code>, inside the <code>&lt;Engine
>           name="Catalina" ...&gt;</code> section, near the
>           <code>RequestDumperValve</code> definition, which is
>           commented out by default:</p>
> 
> <pre class="sample">
> <span class="existing">&lt;!--
> &lt;Valve className="org.apache.catalina.valves.RequestDumperValve"/&gt;
> --&gt;</span>
> 
> &lt;!-- Globus valve for HTTPS+GSI --&gt;
> &lt;Valve className="org.globus.tomcat.coyote.valves.HTTPSValve"/&gt;
> </pre>
>         </li>
>       </ul>
>     </li>
> 
>     <li>
>       <p>Restart Tomcat -- it should now be listening for HTTPS+GSI
>       connections.  Watch for errors in its log file
>       (<code>$CATALINA_HOME/logs/catalina.out</code>).</p>
>     </li>
>   </ol>
> 
>   <p class="header">Metacat Client GSI Login</p> 
> 
>   <ol>
>     <li>
>       <p>You can now use GSI credentials to initiate a Metacat
>       session, replacing <code>Metacat.login(String username, String
>       password)</code> with <code>Metacat.login(GSSCredential
>       credential)</code>.  There are several ways to get a
>       <code>GSSCredential</code>; one easy method, if you have access
>       to a <a href="http://grid.ncsa.uiuc.edu/myproxy/">MyProxy</a>
>       server, is to use the <a href="http://www.cogkit.org/">CoG</a>
>       Java libraries to retrieve a proxy credential from MyProxy.</p>
> 
>       <p>Here is some sample Java code.  Note that it requires, in
>       addition to the JARs listed <a href="#tomcat_jars">above</a>,
>       <code>cog-url-ncsa.jar</code>, which can be found in the
>       <code>metacat/lib</code> directory.</p>
> 
>       <p>Note: for code comments, mouse over the <span class="tooltip"
>       title="like this one">marked</span> sections below.</p>
> 
> <pre class="sample">
> // 1. Get a GSI security credential
> org.globus.myproxy.MyProxy server = new MyProxy(<span class="tooltip" title="Hostname of MyProxy server">host</span>, <span class="tooltip" title="Port number of the MyProxy server -- default is 7512">7512</span>);
> org.ietf.jgss.<span class="tooltip" title="included in standard JRE/JDK libraries">GSSCredential</span> credential = server.get(<span class="tooltip" title="MyProxy username">username</span>, <span class="tooltip" title="MyProxy passphrase">passphrase</span>, <span class="tooltip" title="Credential lifetime in seconds">lifetime</span>);
> 
> // 2. Connect to Metacat via GSI+HTTPS
> String metacatUrl = "https://&lt;metacat server&gt;:8443/metacat/metacat/";
> edu.ucsb.nceas.metacat.client.Metacat client 
>     = edu.ucsb.nceas.metacat.client.MetacatFactory.createMetacatConnection(metacatUrl);
> String loginResult = client.login(credential);
> </pre>
> 
>       <p>The <code>String</code> returned by
>       <code>Metacat.login(GSSCredential)</code> will let you know
>       whether your attempt succeeded.</p>
>     </li>
> 
>     <li>
>       <p>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
>       <code>metacat/src/gsimap.properties</code> and gets deployed to
>       Tomcat's <code>webapps/metacat/WEB-INF/</code> 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.</p>
>     </li>
>   </ol>
> 
>   <p class="header">A Client Inside of Tomcat</p> 
> 
>   <p>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.</p>
> 
>   <ol>
>     <li>
>       You will most likely need to install the Metacat server and the
>       Metacat client application in <i>separate</i> instances of
>       Tomcat in order for them to successfully connect.
>     </li>
> 
>     <li>
>       <p>Protocol Handler Collisions:</p>
> 
>       <p>Short answer: replace "<code>https</code>" with
>       "<code>httpg</code>".</p>
>       <blockquote><pre><code><i>https</i>://&lt;metacat server&gt;:8443/metacat/metacat/</code></pre></blockquote>
>       <p>becomes</p>
>       <blockquote><pre><i>httpg</i>://&lt;metacat server&gt;:8443/metacat/metacat/</pre></blockquote>
> 
>       <p>Long answer: The URL in the example above,
>       <code>https://&lt;metacat server&gt;:8443/metacat/metacat/</code>,
>       uses the <code>HTTPS</code> protocol.  However, actually
>       handling that connection requires a protocol handler that
>       understands GSI+HTTPS instead of plain HTTPS.  Fortunately,
>       <code>static</code> initialization code in
>       <code>MetacatGsiClient</code> specifies a non-default
>       <code>HTTPS</code> handler before the default handler is
>       instantiated by Java.</p>
> 
>       <p>Unfortunately, in Tomcat, an <code>HTTPS</code> 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.</p>
> 
>       <p>Instead, we can define a new protocol.  It could be named
>       anything -- <code>HTTPGSI</code>, <code>METACAT_GSI</code>,
>       <code>GRID_HTTP</code>, etc.  Metacat defines a handler for a
>       protocol named <code>HTTPG</code>.  To see how it works, see the
>       static initialization code in
>       <code>edu.ucsb.nceas.metacat.client.MetacatGsiClient</code> and
>       the very simple class
>       <code>edu.ucsb.nceas.protocols.httpg.Handler</code>.</p>
>     </li>
>     <li>
>       <p>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.</p>
> 
>       <ol style="list-style-type:lower-alpha">
>         <li>
>           Copy <code>metacat.jar</code>, <code>utilities.jar</code>,
>           and <code>cog-url-ncsa.jar</code> from Metacat's lib
>           directory to a place that is accessible by Tomcat, such as
>           <code>$CATALINA_HOME/common/lib</code>.
>         </li>
>         <li>
>           <p>Modify the definition of <code>CLASSPATH</code> in
>           Tomcat's startup script,
>           <code>$CATALINA_HOME/bin/catalina.sh</code> (In Windows,
>           <code>catalina.bat</code>, which has slightly different
>           syntax).</p>
> 
>           <p>Replace:</p>
> <pre class="sample">
> CLASSPATH="$CLASSPATH":"$CATALINA_HOME"/bin/bootstrap.jar:\
> "$CATALINA_HOME"/bin/commons-logging-api.jar
> </pre>
>           <p>With:</p>
> <pre class="sample">
> 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
> </pre>
>         </li>
>       </ol>
> 
> 
>     </li>
>   </ol>
> </td>
> </tr>
> </table>
> 
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 <tt>map</tt>'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("<?xml version=\"1.0\"?>");
---
>             out.println("<?xml version=\"1.0\"?>");
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
<     /**
---
> 	/**
> 	 * <p>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).</p>
> 	 *
> 	 * <p>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.</p>
> 	 *
> 	 * @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.
> 	 *
> 	 * <p>This may be used, depending on the server's configuration, with
> 	 * a PKI Distinguished Name (DN), or with an LDAP name.</p>
> 	 */
> 	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("<login>") == -1) {
<             setSessionId("");
<             throw new MetacatAuthException(response);
<         } else {
<             int start = response.indexOf("<sessionId>") + 11;
<             int end = response.indexOf("</sessionId>");
<             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("<logout>") == -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("<error>") != -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("<error>") != -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("<error>") != -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("<error>") != -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("<error>") != -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("<error>") != -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("<error>") != -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("<error>") != -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("<error>") != -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("<login>") == -1) {
> 			setSessionId("");
> 			throw new MetacatAuthException(response);
> 		} else {
> 			int start = response.indexOf("<sessionId>") + 11;
> 			int end = response.indexOf("</sessionId>");
> 			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.
> 	 *
> 	 * <p>This may be used, depending on the server's configuration, with
> 	 * a PKI Distinguished Name (DN), or with an LDAP name.</p>
> 	 */
> 	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("<logout>") == -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("<error>") != -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("<error>") != -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("<error>") != -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("<error>") != -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("<error>") != -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("<error>") != -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("<error>") != -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("<error>") != -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("<error>") != -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());