001/**
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018
019package org.apache.hadoop.fs.http.server;
020
021import com.google.common.base.Charsets;
022import org.apache.hadoop.classification.InterfaceAudience;
023import org.apache.hadoop.conf.Configuration;
024import org.apache.hadoop.fs.FileSystem;
025import org.apache.hadoop.fs.XAttrCodec;
026import org.apache.hadoop.fs.XAttrSetFlag;
027import org.apache.hadoop.fs.http.client.HttpFSFileSystem;
028import org.apache.hadoop.fs.http.client.HttpFSUtils;
029import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.AccessTimeParam;
030import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.AclPermissionParam;
031import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.BlockSizeParam;
032import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.DataParam;
033import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.DestinationParam;
034import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.FilterParam;
035import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.GroupParam;
036import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.LenParam;
037import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.ModifiedTimeParam;
038import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.OffsetParam;
039import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.OperationParam;
040import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.OverwriteParam;
041import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.OwnerParam;
042import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.PermissionParam;
043import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.RecursiveParam;
044import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.ReplicationParam;
045import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.SourcesParam;
046import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.XAttrEncodingParam;
047import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.XAttrNameParam;
048import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.XAttrSetFlagParam;
049import org.apache.hadoop.fs.http.server.HttpFSParametersProvider.XAttrValueParam;
050import org.apache.hadoop.lib.service.FileSystemAccess;
051import org.apache.hadoop.lib.service.FileSystemAccessException;
052import org.apache.hadoop.lib.service.Groups;
053import org.apache.hadoop.lib.service.Instrumentation;
054import org.apache.hadoop.lib.servlet.FileSystemReleaseFilter;
055import org.apache.hadoop.lib.wsrs.InputStreamEntity;
056import org.apache.hadoop.lib.wsrs.Parameters;
057import org.apache.hadoop.security.UserGroupInformation;
058import org.apache.hadoop.security.token.delegation.web.HttpUserGroupInformation;
059import org.json.simple.JSONObject;
060import org.slf4j.Logger;
061import org.slf4j.LoggerFactory;
062import org.slf4j.MDC;
063
064import javax.ws.rs.Consumes;
065import javax.ws.rs.DELETE;
066import javax.ws.rs.GET;
067import javax.ws.rs.POST;
068import javax.ws.rs.PUT;
069import javax.ws.rs.Path;
070import javax.ws.rs.PathParam;
071import javax.ws.rs.Produces;
072import javax.ws.rs.QueryParam;
073import javax.ws.rs.core.Context;
074import javax.ws.rs.core.MediaType;
075import javax.ws.rs.core.Response;
076import javax.ws.rs.core.UriBuilder;
077import javax.ws.rs.core.UriInfo;
078import java.io.IOException;
079import java.io.InputStream;
080import java.net.URI;
081import java.security.AccessControlException;
082import java.security.PrivilegedExceptionAction;
083import java.text.MessageFormat;
084import java.util.EnumSet;
085import java.util.List;
086import java.util.Map;
087
088/**
089 * Main class of HttpFSServer server.
090 * <p/>
091 * The <code>HttpFSServer</code> class uses Jersey JAX-RS to binds HTTP requests to the
092 * different operations.
093 */
094@Path(HttpFSFileSystem.SERVICE_VERSION)
095@InterfaceAudience.Private
096public class HttpFSServer {
097  private static Logger AUDIT_LOG = LoggerFactory.getLogger("httpfsaudit");
098  private static final Logger LOG = LoggerFactory.getLogger(HttpFSServer.class);
099
100  /**
101   * Executes a {@link FileSystemAccess.FileSystemExecutor} using a filesystem for the effective
102   * user.
103   *
104   * @param ugi user making the request.
105   * @param executor FileSystemExecutor to execute.
106   *
107   * @return FileSystemExecutor response
108   *
109   * @throws IOException thrown if an IO error occurrs.
110   * @throws FileSystemAccessException thrown if a FileSystemAccess releated error occurred. Thrown
111   * exceptions are handled by {@link HttpFSExceptionProvider}.
112   */
113  private <T> T fsExecute(UserGroupInformation ugi, FileSystemAccess.FileSystemExecutor<T> executor)
114    throws IOException, FileSystemAccessException {
115    FileSystemAccess fsAccess = HttpFSServerWebApp.get().get(FileSystemAccess.class);
116    Configuration conf = HttpFSServerWebApp.get().get(FileSystemAccess.class).getFileSystemConfiguration();
117    return fsAccess.execute(ugi.getShortUserName(), conf, executor);
118  }
119
120  /**
121   * Returns a filesystem instance. The fileystem instance is wired for release at the completion of
122   * the current Servlet request via the {@link FileSystemReleaseFilter}.
123   * <p/>
124   * If a do-as user is specified, the current user must be a valid proxyuser, otherwise an
125   * <code>AccessControlException</code> will be thrown.
126   *
127   * @param ugi principal for whom the filesystem instance is.
128   *
129   * @return a filesystem for the specified user or do-as user.
130   *
131   * @throws IOException thrown if an IO error occurred. Thrown exceptions are
132   * handled by {@link HttpFSExceptionProvider}.
133   * @throws FileSystemAccessException thrown if a FileSystemAccess releated error occurred. Thrown
134   * exceptions are handled by {@link HttpFSExceptionProvider}.
135   */
136  private FileSystem createFileSystem(UserGroupInformation ugi)
137      throws IOException, FileSystemAccessException {
138    String hadoopUser = ugi.getShortUserName();
139    FileSystemAccess fsAccess = HttpFSServerWebApp.get().get(FileSystemAccess.class);
140    Configuration conf = HttpFSServerWebApp.get().get(FileSystemAccess.class).getFileSystemConfiguration();
141    FileSystem fs = fsAccess.createFileSystem(hadoopUser, conf);
142    FileSystemReleaseFilter.setFileSystem(fs);
143    return fs;
144  }
145
146  private void enforceRootPath(HttpFSFileSystem.Operation op, String path) {
147    if (!path.equals("/")) {
148      throw new UnsupportedOperationException(
149        MessageFormat.format("Operation [{0}], invalid path [{1}], must be '/'",
150                             op, path));
151    }
152  }
153
154  /**
155   * Special binding for '/' as it is not handled by the wildcard binding.
156   *
157   * @param op the HttpFS operation of the request.
158   * @param params the HttpFS parameters of the request.
159   *
160   * @return the request response.
161   *
162   * @throws IOException thrown if an IO error occurred. Thrown exceptions are
163   * handled by {@link HttpFSExceptionProvider}.
164   * @throws FileSystemAccessException thrown if a FileSystemAccess releated
165   * error occurred. Thrown exceptions are handled by
166   * {@link HttpFSExceptionProvider}.
167   */
168  @GET
169  @Produces(MediaType.APPLICATION_JSON)
170  public Response getRoot(@QueryParam(OperationParam.NAME) OperationParam op,
171                          @Context Parameters params)
172    throws IOException, FileSystemAccessException {
173    return get("", op, params);
174  }
175
176  private String makeAbsolute(String path) {
177    return "/" + ((path != null) ? path : "");
178  }
179
180  /**
181   * Binding to handle GET requests, supported operations are
182   *
183   * @param path the path for operation.
184   * @param op the HttpFS operation of the request.
185   * @param params the HttpFS parameters of the request.
186   *
187   * @return the request response.
188   *
189   * @throws IOException thrown if an IO error occurred. Thrown exceptions are
190   * handled by {@link HttpFSExceptionProvider}.
191   * @throws FileSystemAccessException thrown if a FileSystemAccess releated
192   * error occurred. Thrown exceptions are handled by
193   * {@link HttpFSExceptionProvider}.
194   */
195  @GET
196  @Path("{path:.*}")
197  @Produces({MediaType.APPLICATION_OCTET_STREAM, MediaType.APPLICATION_JSON})
198  public Response get(@PathParam("path") String path,
199                      @QueryParam(OperationParam.NAME) OperationParam op,
200                      @Context Parameters params)
201    throws IOException, FileSystemAccessException {
202    UserGroupInformation user = HttpUserGroupInformation.get();
203    Response response;
204    path = makeAbsolute(path);
205    MDC.put(HttpFSFileSystem.OP_PARAM, op.value().name());
206    switch (op.value()) {
207    case OPEN: {
208      //Invoking the command directly using an unmanaged FileSystem that is
209      // released by the FileSystemReleaseFilter
210      final FSOperations.FSOpen command = new FSOperations.FSOpen(path);
211      final FileSystem fs = createFileSystem(user);
212      InputStream is = null;
213      UserGroupInformation ugi = UserGroupInformation
214          .createProxyUser(user.getShortUserName(),
215              UserGroupInformation.getLoginUser());
216      try {
217        is = ugi.doAs(new PrivilegedExceptionAction<InputStream>() {
218          @Override
219          public InputStream run() throws Exception {
220            return command.execute(fs);
221          }
222        });
223      } catch (InterruptedException ie) {
224        LOG.info("Open interrupted.", ie);
225        Thread.currentThread().interrupt();
226      }
227      Long offset = params.get(OffsetParam.NAME, OffsetParam.class);
228      Long len = params.get(LenParam.NAME, LenParam.class);
229      AUDIT_LOG.info("[{}] offset [{}] len [{}]",
230          new Object[] { path, offset, len });
231      InputStreamEntity entity = new InputStreamEntity(is, offset, len);
232      response =
233          Response.ok(entity).type(MediaType.APPLICATION_OCTET_STREAM).build();
234      break;
235    }
236    case GETFILESTATUS: {
237      FSOperations.FSFileStatus command = new FSOperations.FSFileStatus(path);
238      Map json = fsExecute(user, command);
239      AUDIT_LOG.info("[{}]", path);
240      response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
241      break;
242    }
243    case LISTSTATUS: {
244      String filter = params.get(FilterParam.NAME, FilterParam.class);
245      FSOperations.FSListStatus command =
246          new FSOperations.FSListStatus(path, filter);
247      Map json = fsExecute(user, command);
248      AUDIT_LOG.info("[{}] filter [{}]", path, (filter != null) ? filter : "-");
249      response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
250      break;
251    }
252    case GETHOMEDIRECTORY: {
253      enforceRootPath(op.value(), path);
254      FSOperations.FSHomeDir command = new FSOperations.FSHomeDir();
255      JSONObject json = fsExecute(user, command);
256      AUDIT_LOG.info("");
257      response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
258      break;
259    }
260    case INSTRUMENTATION: {
261      enforceRootPath(op.value(), path);
262      Groups groups = HttpFSServerWebApp.get().get(Groups.class);
263      List<String> userGroups = groups.getGroups(user.getShortUserName());
264      if (!userGroups.contains(HttpFSServerWebApp.get().getAdminGroup())) {
265        throw new AccessControlException(
266            "User not in HttpFSServer admin group");
267      }
268      Instrumentation instrumentation =
269          HttpFSServerWebApp.get().get(Instrumentation.class);
270      Map snapshot = instrumentation.getSnapshot();
271      response = Response.ok(snapshot).build();
272      break;
273    }
274    case GETCONTENTSUMMARY: {
275      FSOperations.FSContentSummary command =
276          new FSOperations.FSContentSummary(path);
277      Map json = fsExecute(user, command);
278      AUDIT_LOG.info("[{}]", path);
279      response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
280      break;
281    }
282    case GETFILECHECKSUM: {
283      FSOperations.FSFileChecksum command =
284          new FSOperations.FSFileChecksum(path);
285      Map json = fsExecute(user, command);
286      AUDIT_LOG.info("[{}]", path);
287      response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
288      break;
289    }
290    case GETFILEBLOCKLOCATIONS: {
291      response = Response.status(Response.Status.BAD_REQUEST).build();
292      break;
293    }
294    case GETACLSTATUS: {
295      FSOperations.FSAclStatus command = new FSOperations.FSAclStatus(path);
296      Map json = fsExecute(user, command);
297      AUDIT_LOG.info("ACL status for [{}]", path);
298      response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
299      break;
300    }
301    case GETXATTRS: {
302      List<String> xattrNames =
303          params.getValues(XAttrNameParam.NAME, XAttrNameParam.class);
304      XAttrCodec encoding =
305          params.get(XAttrEncodingParam.NAME, XAttrEncodingParam.class);
306      FSOperations.FSGetXAttrs command =
307          new FSOperations.FSGetXAttrs(path, xattrNames, encoding);
308      @SuppressWarnings("rawtypes") Map json = fsExecute(user, command);
309      AUDIT_LOG.info("XAttrs for [{}]", path);
310      response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
311      break;
312    }
313    case LISTXATTRS: {
314      FSOperations.FSListXAttrs command = new FSOperations.FSListXAttrs(path);
315      @SuppressWarnings("rawtypes") Map json = fsExecute(user, command);
316      AUDIT_LOG.info("XAttr names for [{}]", path);
317      response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
318      break;
319    }
320    case LISTSTATUS_BATCH: {
321      String startAfter = params.get(
322          HttpFSParametersProvider.StartAfterParam.NAME,
323          HttpFSParametersProvider.StartAfterParam.class);
324      byte[] token = HttpFSUtils.EMPTY_BYTES;
325      if (startAfter != null) {
326        token = startAfter.getBytes(Charsets.UTF_8);
327      }
328      FSOperations.FSListStatusBatch command = new FSOperations
329          .FSListStatusBatch(path, token);
330      @SuppressWarnings("rawtypes") Map json = fsExecute(user, command);
331      AUDIT_LOG.info("[{}] token [{}]", path, token);
332      response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
333      break;
334    }
335    case GETTRASHROOT: {
336      FSOperations.FSTrashRoot command = new FSOperations.FSTrashRoot(path);
337      JSONObject json = fsExecute(user, command);
338      AUDIT_LOG.info("[{}]", path);
339      response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
340      break;
341    }
342    default: {
343      throw new IOException(
344          MessageFormat.format("Invalid HTTP GET operation [{0}]", op.value()));
345    }
346    }
347    return response;
348  }
349
350
351  /**
352   * Binding to handle DELETE requests.
353   *
354   * @param path the path for operation.
355   * @param op the HttpFS operation of the request.
356   * @param params the HttpFS parameters of the request.
357   *
358   * @return the request response.
359   *
360   * @throws IOException thrown if an IO error occurred. Thrown exceptions are
361   * handled by {@link HttpFSExceptionProvider}.
362   * @throws FileSystemAccessException thrown if a FileSystemAccess releated
363   * error occurred. Thrown exceptions are handled by
364   * {@link HttpFSExceptionProvider}.
365   */
366  @DELETE
367  @Path("{path:.*}")
368  @Produces(MediaType.APPLICATION_JSON)
369  public Response delete(@PathParam("path") String path,
370                         @QueryParam(OperationParam.NAME) OperationParam op,
371                         @Context Parameters params)
372    throws IOException, FileSystemAccessException {
373    UserGroupInformation user = HttpUserGroupInformation.get();
374    Response response;
375    path = makeAbsolute(path);
376    MDC.put(HttpFSFileSystem.OP_PARAM, op.value().name());
377    switch (op.value()) {
378      case DELETE: {
379        Boolean recursive =
380          params.get(RecursiveParam.NAME,  RecursiveParam.class);
381        AUDIT_LOG.info("[{}] recursive [{}]", path, recursive);
382        FSOperations.FSDelete command =
383          new FSOperations.FSDelete(path, recursive);
384        JSONObject json = fsExecute(user, command);
385        response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
386        break;
387      }
388      default: {
389        throw new IOException(
390          MessageFormat.format("Invalid HTTP DELETE operation [{0}]",
391                               op.value()));
392      }
393    }
394    return response;
395  }
396
397  /**
398   * Binding to handle POST requests.
399   *
400   * @param is the inputstream for the request payload.
401   * @param uriInfo the of the request.
402   * @param path the path for operation.
403   * @param op the HttpFS operation of the request.
404   * @param params the HttpFS parameters of the request.
405   *
406   * @return the request response.
407   *
408   * @throws IOException thrown if an IO error occurred. Thrown exceptions are
409   * handled by {@link HttpFSExceptionProvider}.
410   * @throws FileSystemAccessException thrown if a FileSystemAccess releated
411   * error occurred. Thrown exceptions are handled by
412   * {@link HttpFSExceptionProvider}.
413   */
414  @POST
415  @Path("{path:.*}")
416  @Consumes({"*/*"})
417  @Produces({MediaType.APPLICATION_JSON})
418  public Response post(InputStream is,
419                       @Context UriInfo uriInfo,
420                       @PathParam("path") String path,
421                       @QueryParam(OperationParam.NAME) OperationParam op,
422                       @Context Parameters params)
423    throws IOException, FileSystemAccessException {
424    UserGroupInformation user = HttpUserGroupInformation.get();
425    Response response;
426    path = makeAbsolute(path);
427    MDC.put(HttpFSFileSystem.OP_PARAM, op.value().name());
428    switch (op.value()) {
429      case APPEND: {
430        Boolean hasData = params.get(DataParam.NAME, DataParam.class);
431        if (!hasData) {
432          response = Response.temporaryRedirect(
433            createUploadRedirectionURL(uriInfo,
434              HttpFSFileSystem.Operation.APPEND)).build();
435        } else {
436          FSOperations.FSAppend command =
437            new FSOperations.FSAppend(is, path);
438          fsExecute(user, command);
439          AUDIT_LOG.info("[{}]", path);
440          response = Response.ok().type(MediaType.APPLICATION_JSON).build();
441        }
442        break;
443      }
444      case CONCAT: {
445        System.out.println("HTTPFS SERVER CONCAT");
446        String sources = params.get(SourcesParam.NAME, SourcesParam.class);
447
448        FSOperations.FSConcat command =
449            new FSOperations.FSConcat(path, sources.split(","));
450        fsExecute(user, command);
451        AUDIT_LOG.info("[{}]", path);
452        System.out.println("SENT RESPONSE");
453        response = Response.ok().build();
454        break;
455      }
456      default: {
457        throw new IOException(
458          MessageFormat.format("Invalid HTTP POST operation [{0}]",
459                               op.value()));
460      }
461    }
462    return response;
463  }
464
465  /**
466   * Creates the URL for an upload operation (create or append).
467   *
468   * @param uriInfo uri info of the request.
469   * @param uploadOperation operation for the upload URL.
470   *
471   * @return the URI for uploading data.
472   */
473  protected URI createUploadRedirectionURL(UriInfo uriInfo, Enum<?> uploadOperation) {
474    UriBuilder uriBuilder = uriInfo.getRequestUriBuilder();
475    uriBuilder = uriBuilder.replaceQueryParam(OperationParam.NAME, uploadOperation).
476      queryParam(DataParam.NAME, Boolean.TRUE);
477    return uriBuilder.build(null);
478  }
479
480
481  /**
482   * Binding to handle PUT requests.
483   *
484   * @param is the inputstream for the request payload.
485   * @param uriInfo the of the request.
486   * @param path the path for operation.
487   * @param op the HttpFS operation of the request.
488   * @param params the HttpFS parameters of the request.
489   *
490   * @return the request response.
491   *
492   * @throws IOException thrown if an IO error occurred. Thrown exceptions are
493   * handled by {@link HttpFSExceptionProvider}.
494   * @throws FileSystemAccessException thrown if a FileSystemAccess releated
495   * error occurred. Thrown exceptions are handled by
496   * {@link HttpFSExceptionProvider}.
497   */
498  @PUT
499  @Path("{path:.*}")
500  @Consumes({"*/*"})
501  @Produces({MediaType.APPLICATION_JSON})
502  public Response put(InputStream is,
503                       @Context UriInfo uriInfo,
504                       @PathParam("path") String path,
505                       @QueryParam(OperationParam.NAME) OperationParam op,
506                       @Context Parameters params)
507    throws IOException, FileSystemAccessException {
508    UserGroupInformation user = HttpUserGroupInformation.get();
509    Response response;
510    path = makeAbsolute(path);
511    MDC.put(HttpFSFileSystem.OP_PARAM, op.value().name());
512    switch (op.value()) {
513      case CREATE: {
514        Boolean hasData = params.get(DataParam.NAME, DataParam.class);
515        if (!hasData) {
516          response = Response.temporaryRedirect(
517            createUploadRedirectionURL(uriInfo,
518              HttpFSFileSystem.Operation.CREATE)).build();
519        } else {
520          Short permission = params.get(PermissionParam.NAME,
521                                         PermissionParam.class);
522          Boolean override = params.get(OverwriteParam.NAME,
523                                        OverwriteParam.class);
524          Short replication = params.get(ReplicationParam.NAME,
525                                         ReplicationParam.class);
526          Long blockSize = params.get(BlockSizeParam.NAME,
527                                      BlockSizeParam.class);
528          FSOperations.FSCreate command =
529            new FSOperations.FSCreate(is, path, permission, override,
530                                      replication, blockSize);
531          fsExecute(user, command);
532          AUDIT_LOG.info(
533            "[{}] permission [{}] override [{}] replication [{}] blockSize [{}]",
534            new Object[]{path, permission, override, replication, blockSize});
535          response = Response.status(Response.Status.CREATED).build();
536        }
537        break;
538      }
539      case SETXATTR: {
540        String xattrName = params.get(XAttrNameParam.NAME, 
541            XAttrNameParam.class);
542        String xattrValue = params.get(XAttrValueParam.NAME, 
543            XAttrValueParam.class);
544        EnumSet<XAttrSetFlag> flag = params.get(XAttrSetFlagParam.NAME, 
545            XAttrSetFlagParam.class);
546
547        FSOperations.FSSetXAttr command = new FSOperations.FSSetXAttr(
548            path, xattrName, xattrValue, flag);
549        fsExecute(user, command);
550        AUDIT_LOG.info("[{}] to xAttr [{}]", path, xattrName);
551        response = Response.ok().build();
552        break;
553      }
554      case REMOVEXATTR: {
555        String xattrName = params.get(XAttrNameParam.NAME, XAttrNameParam.class);
556        FSOperations.FSRemoveXAttr command = new FSOperations.FSRemoveXAttr(
557            path, xattrName);
558        fsExecute(user, command);
559        AUDIT_LOG.info("[{}] removed xAttr [{}]", path, xattrName);
560        response = Response.ok().build();
561        break;
562      }
563      case MKDIRS: {
564        Short permission = params.get(PermissionParam.NAME,
565                                       PermissionParam.class);
566        FSOperations.FSMkdirs command =
567          new FSOperations.FSMkdirs(path, permission);
568        JSONObject json = fsExecute(user, command);
569        AUDIT_LOG.info("[{}] permission [{}]", path, permission);
570        response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
571        break;
572      }
573      case RENAME: {
574        String toPath = params.get(DestinationParam.NAME, DestinationParam.class);
575        FSOperations.FSRename command =
576          new FSOperations.FSRename(path, toPath);
577        JSONObject json = fsExecute(user, command);
578        AUDIT_LOG.info("[{}] to [{}]", path, toPath);
579        response = Response.ok(json).type(MediaType.APPLICATION_JSON).build();
580        break;
581      }
582      case SETOWNER: {
583        String owner = params.get(OwnerParam.NAME, OwnerParam.class);
584        String group = params.get(GroupParam.NAME, GroupParam.class);
585        FSOperations.FSSetOwner command =
586          new FSOperations.FSSetOwner(path, owner, group);
587        fsExecute(user, command);
588        AUDIT_LOG.info("[{}] to (O/G)[{}]", path, owner + ":" + group);
589        response = Response.ok().build();
590        break;
591      }
592      case SETPERMISSION: {
593        Short permission = params.get(PermissionParam.NAME,
594                                      PermissionParam.class);
595        FSOperations.FSSetPermission command =
596          new FSOperations.FSSetPermission(path, permission);
597        fsExecute(user, command);
598        AUDIT_LOG.info("[{}] to [{}]", path, permission);
599        response = Response.ok().build();
600        break;
601      }
602      case SETREPLICATION: {
603        Short replication = params.get(ReplicationParam.NAME,
604                                       ReplicationParam.class);
605        FSOperations.FSSetReplication command =
606          new FSOperations.FSSetReplication(path, replication);
607        JSONObject json = fsExecute(user, command);
608        AUDIT_LOG.info("[{}] to [{}]", path, replication);
609        response = Response.ok(json).build();
610        break;
611      }
612      case SETTIMES: {
613        Long modifiedTime = params.get(ModifiedTimeParam.NAME,
614                                       ModifiedTimeParam.class);
615        Long accessTime = params.get(AccessTimeParam.NAME,
616                                     AccessTimeParam.class);
617        FSOperations.FSSetTimes command =
618          new FSOperations.FSSetTimes(path, modifiedTime, accessTime);
619        fsExecute(user, command);
620        AUDIT_LOG.info("[{}] to (M/A)[{}]", path,
621                       modifiedTime + ":" + accessTime);
622        response = Response.ok().build();
623        break;
624      }
625      case SETACL: {
626        String aclSpec = params.get(AclPermissionParam.NAME,
627                AclPermissionParam.class);
628        FSOperations.FSSetAcl command =
629                new FSOperations.FSSetAcl(path, aclSpec);
630        fsExecute(user, command);
631        AUDIT_LOG.info("[{}] to acl [{}]", path, aclSpec);
632        response = Response.ok().build();
633        break;
634      }
635      case REMOVEACL: {
636        FSOperations.FSRemoveAcl command =
637                new FSOperations.FSRemoveAcl(path);
638        fsExecute(user, command);
639        AUDIT_LOG.info("[{}] removed acl", path);
640        response = Response.ok().build();
641        break;
642      }
643      case MODIFYACLENTRIES: {
644        String aclSpec = params.get(AclPermissionParam.NAME,
645                AclPermissionParam.class);
646        FSOperations.FSModifyAclEntries command =
647                new FSOperations.FSModifyAclEntries(path, aclSpec);
648        fsExecute(user, command);
649        AUDIT_LOG.info("[{}] modify acl entry with [{}]", path, aclSpec);
650        response = Response.ok().build();
651        break;
652      }
653      case REMOVEACLENTRIES: {
654        String aclSpec = params.get(AclPermissionParam.NAME,
655                AclPermissionParam.class);
656        FSOperations.FSRemoveAclEntries command =
657                new FSOperations.FSRemoveAclEntries(path, aclSpec);
658        fsExecute(user, command);
659        AUDIT_LOG.info("[{}] remove acl entry [{}]", path, aclSpec);
660        response = Response.ok().build();
661        break;
662      }
663      case REMOVEDEFAULTACL: {
664        FSOperations.FSRemoveDefaultAcl command =
665                new FSOperations.FSRemoveDefaultAcl(path);
666        fsExecute(user, command);
667        AUDIT_LOG.info("[{}] remove default acl", path);
668        response = Response.ok().build();
669        break;
670      }
671      default: {
672        throw new IOException(
673          MessageFormat.format("Invalid HTTP PUT operation [{0}]",
674                               op.value()));
675      }
676    }
677    return response;
678  }
679
680}