Project

General

Profile

1
/**
2
 *  '$RCSfile$'
3
 *  Copyright: 2000 Regents of the University of California and the
4
 *              National Center for Ecological Analysis and Synthesis
5
 *
6
 *   '$Author: tao $'
7
 *     '$Date: 2003-08-11 18:30:18 -0700 (Mon, 11 Aug 2003) $'
8
 * '$Revision: 1786 $'
9
 *
10
 * This program is free software; you can redistribute it and/or modify
11
 * it under the terms of the GNU General Public License as published by
12
 * the Free Software Foundation; either version 2 of the License, or
13
 * (at your option) any later version.
14
 *
15
 * This program is distributed in the hope that it will be useful,
16
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18
 * GNU General Public License for more details.
19
 *
20
 * You should have received a copy of the GNU General Public License
21
 * along with this program; if not, write to the Free Software
22
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23
 */
24

    
25
package edu.ucsb.nceas.metacat.client;
26

    
27
import java.io.BufferedReader;
28
import java.io.InputStream;
29
import java.io.InputStreamReader;
30
import java.io.PushbackReader;
31
import java.io.IOException;
32
import java.io.StringWriter;
33
import java.io.Reader;
34
import java.net.URL;
35
import java.util.Properties;
36

    
37
import edu.ucsb.nceas.utilities.HttpMessage;
38

    
39
/**
40
 *  This interface provides methods for initializing and logging in to a 
41
 *  Metacat server, and then querying, reading, transforming, inserting, 
42
 *  updating and deleting documents from that server.
43
 */
44
public class MetacatClient implements Metacat
45
{
46
    /** The URL string for the metacat server */
47
    private String metacatUrl;
48

    
49
    /**
50
     * Constructor to create a new instance. Protected because instances
51
     * should only be created by the factory MetacatFactory.
52
     */
53
    protected MetacatClient()
54
    {
55
    }
56

    
57
    /**
58
     *  Method used to log in to a metacat server. Implementations will need
59
     *  to cache a cookie value to make the session persistent.  Each time a
60
     *  call is made to one of the other methods (e.g., read), the cookie will
61
     *  need to be passed back to the metacat server along with the request.
62
     *
63
     *  @param username   the username of the user, like an LDAP DN
64
     *  @param password   the password for that user for authentication
65
     *  @throws MetacatAuthException when the username/password could
66
     *                    not be authenticated
67
     */
68
    public void login(String username, String password) 
69
           throws MetacatAuthException, MetacatInaccessibleException
70
    {
71
        Properties prop = new Properties();
72
        prop.put("action", "login");
73
        prop.put("qformat", "xml");
74
        prop.put("username", username);
75
        prop.put("password", password);
76

    
77
        String response = null;
78
        try {
79
            response = sendDataForString(prop);
80
        } catch (Exception e) {
81
            throw new MetacatInaccessibleException(e.getMessage());
82
        }
83

    
84
        if (response.indexOf("<login>") == -1) {
85
            HttpMessage.setCookie(null);
86
            throw new MetacatAuthException(response);
87
        }
88
    }
89

    
90
    /**
91
     * Read an XML document from the metacat server session, accessed by docid,
92
     * and returned as a Reader.
93
     *
94
     * @param docid the identifier of the document to be read
95
     * @return a Reader for accessing the document
96
     * @throws InsufficientKarmaException when the user has insufficent rights 
97
     *                                    for the operation
98
     * @throws MetacatInaccessibleException when the metacat server can not be
99
     *                                    reached or does not respond
100
     * @throws MetacatException when the metacat server generates another error
101
     */
102
    public Reader read(String docid) throws InsufficientKarmaException,
103
        MetacatInaccessibleException, MetacatException
104
    {
105
        PushbackReader pbr = null;
106

    
107
        Properties prop = new Properties();
108
        prop.put("action", "read");
109
        prop.put("qformat", "xml");
110
        prop.put("docid", docid);
111

    
112
        InputStream response = null;
113
        try {
114
            response = sendData(prop);
115
        } catch (Exception e) {
116
            throw new MetacatInaccessibleException(e.getMessage());
117
        }
118
  
119
        pbr = new PushbackReader(new InputStreamReader(response), 512);
120
        try {
121
            char[] characters = new char[512];
122
            int len = pbr.read(characters, 0, 512);
123
            StringWriter sw = new StringWriter();
124
            sw.write(characters, 0, len);
125
            String message = sw.toString();
126
            sw.close();
127
            pbr.unread(characters, 0, len);
128

    
129
            if (message.indexOf("<error>") != -1) {
130
                if (message.indexOf("does not have permission") != -1) {
131
                    throw new InsufficientKarmaException(message);
132
                } else {
133
                    throw new MetacatException(message);
134
                }
135
            }
136
        } catch (IOException ioe) {
137
            throw new MetacatException(
138
                    "MetacatClient: Error converting Reader to String." 
139
                    + ioe.getMessage());
140
        }
141

    
142
        return pbr;
143
    }
144

    
145
    /**
146
     * Query the metacat document store with the given metacat-compatible 
147
     * query document, and return the result set as a Reader.
148
     *
149
     * @param xmlQuery a Reader for accessing the XML version of the query
150
     * @return a Reader for accessing the result set
151
     */
152
    public Reader query(Reader xmlQuery) throws MetacatInaccessibleException,
153
                                                IOException
154
    {
155
        Reader reader = null;
156
        String query = null;
157
        try
158
        {
159
          query = readerToString(xmlQuery);
160
        }
161
        catch (IOException ioE)
162
        {
163
          throw ioE;
164
        }
165

    
166
        //set up properties
167
        Properties prop = new Properties();
168
        prop.put("action", "squery");
169
        prop.put("qformat", "xml");
170
        prop.put("query", query);
171
        
172
        InputStream response = null;
173
        try {
174
            response = sendData(prop);
175
        } catch (Exception e) {
176
            throw new MetacatInaccessibleException(e.getMessage());
177
        }
178
        reader = new InputStreamReader(response);
179
        return reader;
180
    }
181

    
182
    /**
183
     * Insert an XML document into the repository.
184
     *
185
     * @param docid the docid to insert the document
186
     * @param xmlDocument a Reader for accessing the XML document to be inserted
187
     * @param schema a Reader for accessing the DTD or XML Schema for 
188
     *               the document
189
     * @throws InsufficientKarmaException when the user has insufficent rights 
190
     *                                    for the operation
191
     */
192
    public void insert(String docid, Reader xmlDocument, Reader schema)
193
        throws InsufficientKarmaException
194
    {
195
    }
196

    
197
    /**
198
     * Update an XML document in the repository.
199
     *
200
     * @param docid the docid to update
201
     * @param xmlDocument a Reader for accessing the XML text to be updated
202
     * @param schema a Reader for accessing the DTD or XML Schema for 
203
     *               the document
204
     * @throws InsufficientKarmaException when the user has insufficent rights 
205
     *                                    for the operation
206
     */
207
    public void update(String docid, Reader xmlDocument, Reader schema)
208
        throws InsufficientKarmaException
209
    {
210
    }
211

    
212
    /**
213
     * Delete an XML document in the repository.
214
     *
215
     * @param docid the docid to delete
216
     * @throws InsufficientKarmaException when the user has insufficent rights 
217
     *                                    for the operation
218
     */
219
    public void delete(String docid)
220
        throws InsufficientKarmaException
221
    {
222
    }
223

    
224
    /**
225
     * When the MetacatFactory creates an instance it needs to set the
226
     * MetacatUrl to which connections should be made.
227
     *
228
     * @param metacatUrl the URL for the metacat server
229
     */
230
    public void setMetacatUrl(String metacatUrl)
231
    {
232
        this.metacatUrl = metacatUrl;
233
    }
234

    
235
    /************************************************************************
236
     * PRIVATE METHODS
237
     ************************************************************************/
238

    
239
    /**
240
     * Send a request to metacat.
241
     *
242
     * @param prop the properties to be URL encoded and sent
243
     */
244
    synchronized private InputStream sendDataOnce(Properties prop) 
245
        throws Exception
246
    {
247
        InputStream returnStream = null;
248
        URL url = new URL(metacatUrl);
249
        HttpMessage msg = new HttpMessage(url);
250
        returnStream = msg.sendPostData(prop);
251
        return returnStream;
252
    }
253

    
254
    /**
255
     * Send a request to Metacat
256
     *
257
     * @param prop  the properties to be sent to Metacat
258
     * @return      InputStream as returned by Metacat
259
     */
260
    synchronized private InputStream sendData(Properties prop) throws Exception
261
    {   
262
        InputStream returnStream = null;
263

    
264
        /*
265
            Note:  The reason that there are three try statements all executing
266
            the same code is that there is a problem with the initial connection
267
            using the HTTPClient protocol handler.  These try statements make 
268
            sure that a connection is made because it gives each connection a 
269
            2nd and 3rd chance to work before throwing an error.
270
            THIS IS A TOTAL HACK.  THIS NEEDS TO BE LOOKED INTO AFTER THE BETA1
271
            RELEASE OF MORPHO!!!  cwb (7/24/01)
272
          */
273
        try {
274
           return sendDataOnce(prop);
275
        } catch (Exception e) {
276
            try {
277
                return sendDataOnce(prop);
278
            } catch (Exception e2) {
279
                try {
280
                    return sendDataOnce(prop);
281
                } catch (Exception e3) {
282
                    System.err.println(
283
                            "Failed to send data to metacat 3 times.");
284
                    throw e3;
285
                }
286
            }
287
        }
288
    }
289

    
290
    /**
291
     * Send a request to Metacat
292
     *
293
     * @param prop  the properties to be sent to Metacat
294
     * @return      a string as returned by Metacat
295
     */
296
    synchronized private String sendDataForString(Properties prop) 
297
        throws Exception
298
    {
299
        String response = null;
300

    
301
        try {
302
            InputStreamReader returnStream =
303
                    new InputStreamReader(sendData(prop));
304
            StringWriter sw = new StringWriter();
305
            int len;
306
            char[] characters = new char[512];
307
            while ((len = returnStream.read(characters, 0, 512)) != -1) {
308
                sw.write(characters, 0, len);
309
            }
310
            returnStream.close();
311
            response = sw.toString();
312
            sw.close();
313
        } catch (Exception e) {
314
            throw e;
315
        }
316
        return response;
317
    }
318
    /**
319
     * Utility method to convert a reader to a String.
320
     *
321
     * @param reader the Reader to be converted
322
     * @return a String representation fo the data read
323
     */
324
    private String readerToString(Reader reader) throws IOException
325
    {
326
        String response = null;
327

    
328
        try {
329
            StringWriter sw = new StringWriter();
330
            int len;
331
            char[] characters = new char[512];
332
            while ((len = reader.read(characters, 0, 512)) != -1) {
333
                sw.write(characters, 0, len);
334
            }
335
            response = sw.toString();
336
            sw.close();
337
            reader.close();
338
        } catch (IOException e) {
339
            throw e;
340
        }
341
        return response;
342
    }
343
    
344
}
(4-4/7)