Java tutorial
/** * Copyright 2014-2015 SHAF-WORK * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.shaf.server.controller; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.Collection; import java.util.Map; import org.shaf.core.content.DescriptionContent; import org.shaf.core.content.ErrorContent; import org.shaf.core.content.ProgressContent; import org.shaf.core.content.ProtocolContent; import org.shaf.core.content.ReceiptContent; import org.shaf.core.content.StructuredContent; import org.shaf.core.content.UnstructuredContent; import org.shaf.core.io.storage.StorageDriver; import org.shaf.core.io.storage.StorageType; import org.shaf.core.net.NetworkContentException; import org.shaf.core.net.NetworkTransformer; import org.shaf.core.security.Firewall; import org.shaf.core.security.Role; import org.shaf.core.util.ClassUtils; import org.shaf.core.util.Log; import org.shaf.core.util.TextMatrix; import org.shaf.core.util.UriUtils; import org.springframework.core.io.InputStreamResource; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.multipart.MultipartFile; import com.google.common.io.ByteStreams; /** * The controller for processing actions sending from the command-line shell. * * @author Mykola Galushka */ @Controller @RequestMapping("/cmd") public class CmdActionController extends GenericActionController { /** * Defines a logger. */ private static final Log LOG = Log.forClass(CmdActionController.class); /** * Tests if the specified role is available for the established connection. * * @param name * the role name to check. * @return {@code true} if the role is avaliable and {@code false} * otherwise. * @throws Exception * if an error occurs. */ @RequestMapping(value = "/role/{name}", method = RequestMethod.GET) public @ResponseBody String onRole(@PathVariable String name) throws Exception { LOG.debug("CALL: /cmd/role/{" + name + "}"); long start = 0, finish = 0; try { boolean flag = false; start = System.currentTimeMillis(); Role role = Role.findRole(name); if (role != null) { flag = super.getFirewall().isAllowed(role); } finish = System.currentTimeMillis(); return NetworkTransformer.getTransport(new UnstructuredContent(finish - start, String.valueOf(flag))); } catch (Exception exc) { String message = "Failed to obtain asscess status for '" + name + "' role."; LOG.fatal(message, exc); return NetworkTransformer.getTransport(new ErrorContent(finish - start, message)); } } /** * Returns the {@link StructuredContent structured content} containing * information about specified category. * * @param category * the listing category. * @return the XML with structured content. * @throws Exception * if an error occurs. */ @RequestMapping(value = "/list/{category}", method = RequestMethod.GET) public @ResponseBody String onList(@PathVariable String category) throws Exception { LOG.debug("CALL: /cmd/list/{" + category + "}"); Firewall firewall = super.getFirewall(); String username = super.getUserName(); long start = 0, finish = 0; try { TextMatrix info = null; start = System.currentTimeMillis(); if ("applications".equals(category)) { firewall.allow(Role.ADMIN); info = OPER.getApplications(); } else if ("processes".equals(category)) { firewall.allow(Role.ADMIN, Role.USER); info = OPER.getProcesses("all"); } else if ("jobs".equals(category)) { firewall.allow(Role.USER); info = OPER.getJobs(); } else if ("uploads".equals(category)) { firewall.allow(Role.PROVIDER); info = OPER.getStorages(firewall, username, StorageType.PROVIDER.getName(), "all"); } else if ("downloads".equals(category)) { firewall.allow(Role.CONSUMER); info = OPER.getStorages(firewall, username, StorageType.CONSUMER.getName(), "all"); } finish = System.currentTimeMillis(); return NetworkTransformer.getTransport(new StructuredContent(finish - start, info)); } catch (Exception exc) { String message = "Failed to list '" + category + "' category."; LOG.fatal(message, exc); return NetworkTransformer.getTransport(new ErrorContent(finish - start, message)); } } /** * Returns the process {@link DescriptionContent description} for the * specified process alias. * * @param alias * the process alias. * @return the process description. * @throws Exception * if an error occurs. */ @RequestMapping(value = "/descr/{alias}", method = RequestMethod.GET, produces = "text/xml") public @ResponseBody String onDescription(@PathVariable String alias) throws Exception { LOG.debug("CALL service: /descr/" + alias); long start = 0, finish = 0; try { super.getFirewall().allow(Role.ADMIN, Role.USER); start = System.currentTimeMillis(); DescriptionContent content = OPER.getProcessDescr(alias); finish = System.currentTimeMillis(); return NetworkTransformer.getTransport(content); } catch (Exception exc) { String message = "Failed to obtain the '" + alias + "' process description."; LOG.fatal(message, exc); return NetworkTransformer.getTransport(new ErrorContent(finish - start, message)); } } /** * Submits the specified process for execution and returns launching * {@link ReceiptContent receipt}. * * @param alias * the process alias. * @param args * the process arguments. * @return the receipt about successful submit operation. * @throws Exception * if an error occurs. */ @RequestMapping(value = "/submit/{alias}/{arguments}", method = RequestMethod.GET, produces = "text/xml") public @ResponseBody String onSubmit(@PathVariable String alias, @PathVariable String arguments) throws Exception { LOG.debug("CALL service: /submit/run/{" + alias + "}/{" + UriUtils.decodeArguments(arguments) + "}"); long start = 0, finish = 0; try { super.getFirewall().allow(Role.USER); start = System.currentTimeMillis(); ReceiptContent content = new ReceiptContent( OPER.launchProcess(alias, UriUtils.decodeArguments(arguments))); finish = System.currentTimeMillis(); return NetworkTransformer.getTransport(content); } catch (Exception exc) { String message = "Failed to submit '" + alias + "' process for execution."; LOG.fatal(message, exc); return NetworkTransformer.getTransport(new ErrorContent(finish - start, message)); } } /** * Forces to forget the specified job. * * @param id * the job ID. * @return the receipt about successful forget operation. * @throws Exception * if an error occurs. */ @RequestMapping(value = "/outcome/{id}", method = RequestMethod.GET, produces = "text/xml") public @ResponseBody String onOutcome(@PathVariable String id) throws Exception { LOG.debug("CALL service: /cmd/outcome/{" + id + "}"); long start = 0, finish = 0; try { super.getFirewall().allow(Role.USER); start = System.currentTimeMillis(); ProtocolContent content = null; if (OPER.isJobAvailable(id)) { /* * Gets the job execution time. */ long time = OPER.getJobExecutionTime(id); /* * Gets the current gob outcome. */ if (!OPER.isJobActive(id)) { Object outcome = OPER.getJobOutcome(id); if (outcome == null) { /* * The job is completed without any outcome. In this * case we prepare just a simple message to indicate * that this job is done. */ content = new UnstructuredContent(time, "done"); } else if (outcome instanceof Exception) { /* * If the job execution is failed, the outcome receives * an exception. The following code constructs the * error-content, which includes information about * occurred exception. */ content = new ErrorContent(time, outcome.toString()); } else if (ClassUtils.isCollection(outcome)) { /* * If the job outcome is Collection, we assume, that * this is a structured data, which can be converted * into the table (with only one column). It allows to * prepared the structured content by the following * code. */ content = new StructuredContent(time, TextMatrix.create((Collection<?>) outcome)); } else if (ClassUtils.isMap(outcome)) { /* * If the job outcome is Map, we assume, that this is a * structured data, which can be converted into the * table (with only two columns - first for keys and * second for values). It allows to prepared the * structured content by the following code. */ content = new StructuredContent(time, TextMatrix.create((Map<?, ?>) outcome)); } else if (outcome instanceof TextMatrix) { /* * If the job outcome is Table, we assume, that this is * a structured data (containing certain amount columns * and rows). It allows to prepared the structured * content by the following code. */ content = new StructuredContent(time, (TextMatrix) outcome); } else { /* * For anything else the unstructured content is * created. */ content = new UnstructuredContent(time, outcome.toString()); } } else { /* * If the job still running it returns the progress content. */ content = new ProgressContent(time, OPER.getJobProgress(id)); } } finish = System.currentTimeMillis(); return NetworkTransformer.getTransport(content); } catch (Exception exc) { String message = "Failed to obtain the process outcome from job #" + id + "."; LOG.fatal(message, exc); return NetworkTransformer.getTransport(new ErrorContent(finish - start, message)); } } /** * Forces to forget the specified job. * * @param id * the job ID. * @return the receipt about successful forget operation. * @throws Exception * if an error occurs. */ @RequestMapping(value = "/forget/{id}", method = RequestMethod.GET, produces = "text/xml") public @ResponseBody String onForget(@PathVariable String id) throws Exception { LOG.debug("CALL service: /cmd/forget/{" + id + "}"); long start = 0, finish = 0; try { super.getFirewall().allow(Role.USER); start = System.currentTimeMillis(); OPER.removeJob(id); finish = System.currentTimeMillis(); return NetworkTransformer.getTransport(new ReceiptContent(id)); } catch (Exception exc) { String message = "Failed to forget job #" + id + "."; LOG.fatal(message, exc); return NetworkTransformer.getTransport(new ErrorContent(finish - start, message)); } } // ======================================================================== // Provider Functions // ======================================================================== /** * Puts data to the server. * * @param storage * the storage type. * @param alias * the data alias. * @param data * the data to upload. * @throws NetworkContentException * @throws Exception * if an error occurs. */ @RequestMapping(value = "/upload/{storage}/{alias}", method = RequestMethod.POST) public void onUpload(@PathVariable String storage, @PathVariable String alias, @RequestBody MultipartFile data) throws Exception { LOG.debug("CALL service: /cmd/upload/{" + storage + "}/{" + alias + "} with attached data."); LOG.trace("The attached data: " + data); if (data.isEmpty()) { LOG.warn("There no providing data."); } else { Firewall firewall = super.getFirewall(); String username = super.getUserName(); StorageDriver driver = OPER.getStorageDriver(firewall, username, StorageType.PROVIDER, storage); LOG.trace("Driver for uploading: " + driver); LOG.trace("Uploading data name: " + data.getName()); LOG.trace("Uploading data size: " + data.getSize()); try (InputStream in = data.getInputStream(); OutputStream out = driver.getOutputStream(alias)) { ByteStreams.copy(in, out); } catch (IOException exc) { throw exc; } } } // ======================================================================== // Consumer Functions // ======================================================================== /** * Gets data from the server. * * @param storage * the resource type. * @param alias * the data alias. * @return the entity for downloading data. * @throws Exception * if an error occurs. */ @RequestMapping(value = "/download/{storage}/{alias}", method = RequestMethod.GET) public @ResponseBody ResponseEntity<InputStreamResource> onDownload(@PathVariable String storage, @PathVariable String alias) throws Exception { LOG.debug("CALL service: /cmd/download/{" + storage + "}/{" + alias + "}"); Firewall firewall = super.getFirewall(); String username = super.getUserName(); StorageDriver driver = OPER.getStorageDriver(firewall, username, StorageType.CONSUMER, storage); HttpHeaders header = new HttpHeaders(); header.setContentType(MediaType.APPLICATION_OCTET_STREAM); header.setContentLength(driver.getLength(alias)); header.setContentDispositionFormData("attachment", alias); return new ResponseEntity<InputStreamResource>(new InputStreamResource(driver.getInputStream(alias)), header, HttpStatus.OK); } }