Project

General

Profile

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

    
25
import java.io.File;
26
import java.io.IOException;
27
import java.io.InputStream;
28
import java.io.OutputStream;
29
import java.io.PrintWriter;
30
import java.text.DateFormat;
31
import java.text.ParseException;
32
import java.text.SimpleDateFormat;
33
import java.util.Date;
34
import java.util.Enumeration;
35
import java.util.Hashtable;
36
import java.util.TimeZone;
37
import java.util.Timer;
38

    
39
import javax.servlet.ServletContext;
40
import javax.servlet.http.HttpServletRequest;
41
import javax.servlet.http.HttpServletResponse;
42

    
43
import org.apache.commons.io.IOUtils;
44
import org.apache.log4j.Logger;
45
import org.dataone.client.auth.CertificateManager;
46
import org.dataone.service.exceptions.BaseException;
47
import org.dataone.service.types.Session;
48
import org.dataone.service.types.util.ServiceTypeUtil;
49
import org.jibx.runtime.JiBXException;
50

    
51
import edu.ucsb.nceas.metacat.MetacatHandler;
52
import edu.ucsb.nceas.metacat.properties.PropertyService;
53
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
54
/**
55
 * 
56
 * Base class for handling D1 REST calls in Metacat
57
 * 
58
 * @author leinfelder
59
 */
60
public class D1ResourceHandler {
61

    
62
    /**HTTP Verb GET*/
63
    public static final byte GET = 1;
64
    /**HTTP Verb POST*/
65
    public static final byte POST = 2;
66
    /**HTTP Verb PUT*/
67
    public static final byte PUT = 3;
68
    /**HTTP Verb DELETE*/
69
    public static final byte DELETE = 4;
70
    /**HTTP Verb HEAD*/
71
    public static final byte HEAD = 5;
72

    
73
    /*
74
     * API Resources
75
     */
76
    protected static final String RESOURCE_OBJECTS = "object";
77
    protected static final String RESOURCE_FORMATS = "formats";
78
    protected static final String RESOURCE_META = "meta";
79
    protected static final String RESOURCE_SESSION = "session";
80
    protected static final String RESOURCE_IDENTIFIER = "identifier";
81
    protected static final String RESOURCE_LOG = "log";
82
    protected static final String RESOURCE_CHECKSUM = "checksum";
83
    protected static final String RESOURCE_MONITOR = "monitor";
84
    protected static final String RESOURCE_BASE_URL = "d1";
85
    protected static final String RESOURCE_REPLICATE = "replicate";
86
    
87
    protected static final String RESOURCE_IS_AUTHORIZED = "isAuthorized";
88
    protected static final String RESOURCE_ACCESS_RULES = "accessRules";
89

    
90
    /*
91
     * API Functions used as URL parameters
92
     */
93
    protected static final String FUNCTION_KEYWORD = "op";
94
    protected static final String FUNCTION_NAME_LOGIN = "login";
95
    protected static final String FUNCTION_NAME_LOGOUT = "logout";
96
    protected static final String FUNCTION_NAME_SET_ACCESS = "setaccess";
97
    protected static final String FUNCTION_NAME_ISREGISTERED = "isregistered";
98
    protected static final String FUNCTION_NAME_GETALLDOCS = "getalldocids";
99
    protected static final String FUNCTION_NAME_GETNEXTREV = "getnextrevision";
100
    protected static final String FUNCTION_NAME_GETNEXTOBJ = "getnextobject";
101
    protected static final String FUNCTION_NAME_INSERT = "insert";
102
    protected static final String FUNCTION_NAME_UPDATE = "update";
103
    protected static final String FUNCTION_NAME_GENERATE_MISSING_SYSTEM_METADATA = "generatemissingsystemmetadata";
104

    
105
    protected static final DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
106
    
107
    protected ServletContext servletContext;
108
    protected Logger logMetacat;
109
    protected MetacatHandler handler;
110
    protected HttpServletRequest request;
111
    protected HttpServletResponse response;
112
    protected String username;
113
    protected String password;
114
    protected String sessionId;
115
    protected String[] groupNames;
116

    
117
    protected Hashtable<String, String[]> params;
118
    
119
    // D1 certificate-based authentication
120
    protected Session session;
121

    
122
    /**Initializes new instance by setting servlet context,request and response*/
123
    public D1ResourceHandler(ServletContext servletContext,
124
            HttpServletRequest request, HttpServletResponse response) {
125
        this.servletContext = servletContext;
126
        this.request = request;
127
        this.response = response;
128
    }
129

    
130
    /**
131
     * This function is called from REST API servlet and handles each request 
132
     * 
133
     * @param httpVerb (GET, POST, PUT or DELETE)
134
     */
135
    public void handle(byte httpVerb) {
136
        logMetacat = Logger.getLogger(D1ResourceHandler.class);
137
        try {
138
  
139
            // load session from certificate in request
140
            session = CertificateManager.getInstance().getSession(request);
141

    
142
            // initialize the parameters
143
            params = new Hashtable<String, String[]>();
144
            initParams();
145

    
146
            // create the handler for interacting with Metacat
147
            Timer timer = new Timer();
148
            handler = new MetacatHandler(timer);
149

    
150
        } catch (Exception e) {
151
        	// TODO: more D1 structure when failing here
152
        	response.setStatus(400);
153
            printError("Incorrect resource!", response);
154
            logMetacat.error(e.getClass() + ": " + e.getMessage(), e);
155
        }
156
    }
157
    
158
		/**
159
     *  copies request parameters to a hashtable which is given as argument to native metacathandler functions  
160
     */
161
    protected void initParams() {
162

    
163
        String name = null;
164
        String[] value = null;
165
        Enumeration paramlist = request.getParameterNames();
166
        while (paramlist.hasMoreElements()) {
167
            name = (String) paramlist.nextElement();
168
            value = request.getParameterValues(name);
169
            params.put(name, value);
170
        }
171
    }
172

    
173
    /**
174
     * parse a date and return it in GMT if it ends with a 'Z'
175
     * @param date
176
     * @return
177
     * @throws ParseException
178
     */
179
    protected Date parseDateAndConvertToGMT(String date) throws ParseException
180
    {
181
        try
182
        {   //the format we want
183
            return dateFormat.parse(date);
184
        }
185
        catch(java.text.ParseException pe)
186
        {   //try another legacy format
187
            DateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss'Z'");
188
            dateFormat2.setTimeZone(TimeZone.getTimeZone("GMT-0"));
189
            return dateFormat2.parse(date);
190
        }    
191
    }
192

    
193
    /**
194
     * serialize an object of type to out
195
     * @param type the class of the object to serialize (i.e. SystemMetadata.class)
196
     * @param object the object to serialize
197
     * @param out the stream to serialize it to
198
     * @throws JiBXException
199
     */
200
    protected void serializeServiceType(Class type, Object object, OutputStream out)
201
      throws JiBXException {
202
        ServiceTypeUtil.serializeServiceType(type, object, out);
203
    }
204
    
205
    /**
206
     * deserialize an object of type from is
207
     * @param type the class of the object to serialize (i.e. SystemMetadata.class)
208
     * @param is the stream to deserialize from
209
     * @throws JiBXException
210
     */
211
    protected Object deserializeServiceType(Class type, InputStream is)
212
      throws JiBXException {
213
        return ServiceTypeUtil.deserializeServiceType(type, is);
214
    }
215
        
216
    /**
217
     * locate the boundary marker for an MMP
218
     * @param is
219
     * @return
220
     * @throws IOException
221
     */
222
    protected static String[] findBoundaryString(InputStream is)
223
        throws IOException {
224
        String[] endResult = new String[2];
225
        String boundary = "";
226
        String searchString = "boundary=";
227
        byte[] b = new byte[1024];
228
        int numbytes = is.read(b, 0, 1024);
229

    
230
        while(numbytes != -1)
231
        {
232
            String s = new String(b, 0, numbytes);
233
            int searchStringIndex = s.indexOf(searchString);
234
            
235
            if(s.indexOf("\"", searchStringIndex + searchString.length() + 1) == -1)
236
            { //the end of the boundary is in the next byte array
237
                boundary = s.substring(searchStringIndex + searchString.length() + 1, s.length());
238
            }
239
            else if(!boundary.startsWith("--"))
240
            { //we can read the whole boundary from this byte array
241
                boundary = s.substring(searchStringIndex + searchString.length() + 1, 
242
                    s.indexOf("\"", searchStringIndex + searchString.length() + 1));
243
                boundary = "--" + boundary;
244
                endResult[0] = boundary;
245
                endResult[1] = s.substring(s.indexOf("\"", searchStringIndex + searchString.length() + 1) + 1,
246
                        s.length());
247
                break;
248
            }
249
            else
250
            { //we're now reading the 2nd byte array to get the rest of the boundary
251
                searchString = "\"";
252
                searchStringIndex = s.indexOf(searchString);
253
                boundary += s.substring(0, searchStringIndex);
254
                boundary = "--" + boundary;
255
                endResult[0] = boundary;
256
                endResult[1] = s.substring(s.indexOf("\"", searchStringIndex + searchString.length() + 1) + 1,
257
                        s.length());
258
                break;
259
            }
260
        }
261
        System.out.println("boundary is: '" + boundary + "'");
262
        return endResult;
263
    }
264
    
265
    /**
266
     * return the directory where temp files are stored
267
     * @return
268
     */
269
    protected static File getTempDirectory()
270
    {
271
        File tmpDir = null;
272
        Logger logMetacat = Logger.getLogger(D1ResourceHandler.class);
273
        try {
274
            tmpDir = new File(PropertyService.getProperty("application.tempDir"));
275
        }
276
        catch(PropertyNotFoundException pnfe) {
277
            logMetacat.error("D1ResourceHandler.writeMMPPartstoFiles: " +
278
                    "application.tmpDir not found.  Using /tmp instead.");
279
            tmpDir = new File("/tmp");
280
        }
281
        return tmpDir;
282
    }
283
    
284
    /**
285
     * Prints xml response
286
     * @param message Message to be displayed
287
     * @param response Servlet response that xml message will be printed 
288
     * */
289
    protected void printError(String message, HttpServletResponse response) {
290
        try {
291
            logMetacat.error("D1ResourceHandler: Printing error to servlet response: " + message);
292
            PrintWriter out = response.getWriter();
293
            response.setContentType("text/xml");
294
            out.println("<?xml version=\"1.0\"?>");
295
            out.println("<error>");
296
            out.println(message);
297
            out.println("</error>");
298
            out.close();
299
        } catch (IOException e) {
300
            e.printStackTrace();
301
        }
302
    }
303
    
304
    /**
305
     * serialize a D1 exception using jibx
306
     * @param e
307
     * @param out
308
     */
309
    protected void serializeException(BaseException e, OutputStream out) {
310
        // TODO: Use content negotiation to determine which return format to use
311
        response.setContentType("text/xml");
312
        response.setStatus(e.getCode());
313
        
314
        logMetacat.error("D1ResourceHandler: Serializing exception with code " + e.getCode() + ": " + e.getMessage());
315
        e.printStackTrace();
316
        
317
        try {
318
            IOUtils.write(e.serialize(BaseException.FMT_XML), out);
319
        } catch (IOException e1) {
320
            logMetacat.error("Error writing exception to stream. " 
321
                    + e1.getMessage());
322
        }
323
    }
324

    
325
}
(4-4/11)