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