001/** 002 * Copyright 2016 Tampere University of Technology, Pori Department 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package service.tut.pori.apilta.sensors.reference; 017 018import java.io.IOException; 019import java.io.InputStream; 020 021import org.apache.commons.io.IOUtils; 022import org.apache.log4j.Logger; 023 024import service.tut.pori.apilta.files.datatypes.FileDetails; 025import service.tut.pori.apilta.files.datatypes.FileDetailsList; 026import service.tut.pori.apilta.sensors.datatypes.SensorTask; 027import core.tut.pori.http.Response; 028import core.tut.pori.http.annotations.HTTPAuthenticationParameter; 029import core.tut.pori.http.annotations.HTTPMethodParameter; 030import core.tut.pori.http.annotations.HTTPService; 031import core.tut.pori.http.annotations.HTTPServiceMethod; 032import core.tut.pori.http.parameters.AuthenticationParameter; 033import core.tut.pori.http.parameters.DataGroups; 034import core.tut.pori.http.parameters.InputStreamParameter; 035import core.tut.pori.http.parameters.Limits; 036import core.tut.pori.http.parameters.LongParameter; 037import core.tut.pori.http.parameters.StringParameter; 038import core.tut.pori.utils.XMLFormatter; 039 040/** 041 * 042 * Reference implementation for Server APIs. 043 * 044 * <h1>Implementation Service path {@value service.tut.pori.apilta.sensors.Definitions#SERVICE_SENSORS}</h1> 045 * 046 * @see service.tut.pori.apilta.sensors.SensorService 047 * 048 */ 049@HTTPService(name = Definitions.SERVICE_SENSORS_REFERENCE_SERVER) 050public class ServerService { 051 private static final Logger LOGGER = Logger.getLogger(ServerService.class); 052 private XMLFormatter _formatter = new XMLFormatter(); 053 054 /** 055 * The request is to be sent in the body of POST method. The Content-Type header MUST be set to "text/xml". The character set MUST be UTF-8. For example, "Content-Type: text/xml; charset=UTF-8". 056 * 057 * The method can be called multiple times by the back-ends. Each call is assumed to be an incremental update on the previous one and can contain any amount of new information. 058 * 059 * <h2>Example Query:</h2> 060 * 061 * POST /rest/{@value service.tut.pori.apilta.sensors.reference.Definitions#SERVICE_SENSORS_REFERENCE_SERVER}/{@value service.tut.pori.tasks.Definitions#METHOD_TASK_FINISHED}<br> 062 * Content-Type: text/xml; charset=UTF-8<br><br> 063 * 064 * <b>[HTTP BODY STARTS]</b><br> 065 * 066 * {@doc.restlet service="[service.tut.pori.apilta.sensors.reference.Definitions#SERVICE_SENSORS_REFERENCE_EXAMPLE]" method="[service.tut.pori.apilta.sensors.reference.Definitions#METHOD_TASK_RESULTS]" type="GET" query="" body_uri=""} <br> 067 * 068 * <b>[HTTP BODY ENDS]</b><br> 069 * 070 * <h2>Example Result:</h2> 071 * 072 * {@doc.restlet service="[service.tut.pori.apilta.sensors.reference.Definitions#SERVICE_SENSORS_REFERENCE_SERVER]" method="[service.tut.pori.tasks.Definitions#METHOD_TASK_FINISHED]" type="POST" query="" body_uri="[service.tut.pori.apilta.sensors.reference.Definitions#SERVICE_SENSORS_REFERENCE_EXAMPLE]/[service.tut.pori.apilta.sensors.reference.Definitions#METHOD_TASK_RESULTS]?[core.tut.pori.http.parameters.DataGroups#PARAMETER_DEFAULT_NAME]=[service.tut.pori.apilta.sensors.Definitions#DATA_GROUP_DATA_POINTS]"} 073 * 074 * @param authenticatedUser 075 * @param xml Only the result data should be in the body. See {@link service.tut.pori.apilta.sensors.datatypes.SensorTask} 076 */ 077 @HTTPServiceMethod(name = service.tut.pori.tasks.Definitions.METHOD_TASK_FINISHED, acceptedMethods={core.tut.pori.http.Definitions.METHOD_POST}) 078 public void taskFinished ( 079 @HTTPAuthenticationParameter(required = false) AuthenticationParameter authenticatedUser, 080 @HTTPMethodParameter(name = InputStreamParameter.PARAMETER_DEFAULT_NAME, bodyParameter = true) InputStreamParameter xml 081 ) 082 { 083 try { 084 String body = IOUtils.toString(xml.getValue(), core.tut.pori.http.Definitions.CHARSET_UTF8); // read the body 085 LOGGER.debug(body); // print to debug 086 try(InputStream input = IOUtils.toInputStream(body, core.tut.pori.http.Definitions.CHARSET_UTF8)){ // convert back to stream for unmarshal 087 SensorsReferenceCore.taskFinished(authenticatedUser.getUserIdentity(), _formatter.toObject(input, SensorTask.class)); 088 } 089 } catch (IOException ex) { 090 LOGGER.error(ex, ex); 091 } 092 } 093 094 /** 095 * This method can be used to retrieve the up-to-date details and progress of a previously scheduled task. 096 * 097 * <h2>Example Query:</h2> 098 * 099 * GET /rest/{@value service.tut.pori.apilta.sensors.reference.Definitions#SERVICE_SENSORS_REFERENCE_SERVER}/{@value service.tut.pori.tasks.Definitions#METHOD_QUERY_TASK_DETAILS}?{@value service.tut.pori.tasks.Definitions#PARAMETER_BACKEND_ID}=1&{@value service.tut.pori.tasks.Definitions#PARAMETER_TASK_ID}=1<br> 100 * 101 * <h2>Example Result:</h2> 102 * 103 * {@doc.restlet service="[service.tut.pori.apilta.sensors.reference.Definitions#SERVICE_SENSORS_REFERENCE_SERVER]" method="[service.tut.pori.tasks.Definitions#METHOD_QUERY_TASK_DETAILS]" type="GET" query="[service.tut.pori.tasks.Definitions#PARAMETER_BACKEND_ID]=1&[service.tut.pori.tasks.Definitions#PARAMETER_TASK_ID]=1" body_uri=""} 104 * 105 * @param authenticatedUser 106 * @param taskId 107 * @param backendId 108 * @param dataGroups 109 * @param limits paging limits 110 * @return response See {@link service.tut.pori.apilta.sensors.datatypes.SensorTask} 111 */ 112 @HTTPServiceMethod(name = service.tut.pori.tasks.Definitions.METHOD_QUERY_TASK_DETAILS, acceptedMethods={core.tut.pori.http.Definitions.METHOD_GET}) 113 public Response queryTaskDetails( 114 @HTTPAuthenticationParameter(required = false) AuthenticationParameter authenticatedUser, 115 @HTTPMethodParameter(name = service.tut.pori.tasks.Definitions.PARAMETER_BACKEND_ID) LongParameter backendId, 116 @HTTPMethodParameter(name = service.tut.pori.tasks.Definitions.PARAMETER_TASK_ID) StringParameter taskId, 117 @HTTPMethodParameter(name = DataGroups.PARAMETER_DEFAULT_NAME, required = false) DataGroups dataGroups, 118 @HTTPMethodParameter(name = Limits.PARAMETER_DEFAULT_NAME, required = false) Limits limits 119 ) 120 { 121 return new Response(SensorsReferenceCore.queryTaskDetails(authenticatedUser.getUserIdentity(), backendId.getValue(), dataGroups, limits, taskId.getValues(), service.tut.pori.apilta.sensors.Definitions.TASK_TYPE_DATA_COLLECT)); // we can simply return pseudo randomly generated task details with hard-coded task type 122 } 123 124 /** 125 * The request is to be sent in the body of POST method. 126 * 127 * <h2>Example Query:</h2> 128 * 129 * POST /rest/{@value service.tut.pori.apilta.sensors.reference.Definitions#SERVICE_SENSORS_REFERENCE_SERVER}/{@value service.tut.pori.apilta.sensors.Definitions#METHOD_CREATE_FILE}?{@value service.tut.pori.tasks.Definitions#PARAMETER_BACKEND_ID}=1<br> 130 * Content-Type: text/xml; charset=UTF-8<br><br> 131 * 132 * <b>[HTTP BODY STARTS]</b><br> 133 * 134 * [ANY FILE CONTENT] <br> 135 * 136 * <b>[HTTP BODY ENDS]</b><br> 137 * 138 * <h2>Example Result:</h2> 139 * 140 * {@doc.restlet service="[service.tut.pori.apilta.sensors.reference.Definitions#SERVICE_SENSORS_REFERENCE_SERVER]" method="[service.tut.pori.apilta.sensors.Definitions#METHOD_CREATE_FILE]" type="POST" query="[service.tut.pori.tasks.Definitions#PARAMETER_BACKEND_ID]=1" body_uri="[service.tut.pori.apilta.sensors.reference.Definitions#SERVICE_SENSORS_REFERENCE_EXAMPLE]/[service.tut.pori.tasks.Definitions#ELEMENT_TASK]"} 141 * 142 * @param authenticatedUser 143 * @param backendId 144 * @param file only the file contents should be in the body. 145 * @return {@link service.tut.pori.apilta.files.datatypes.FileDetailsList} with identifier for the generated file 146 */ 147 @HTTPServiceMethod(name = service.tut.pori.apilta.sensors.Definitions.METHOD_CREATE_FILE, acceptedMethods={core.tut.pori.http.Definitions.METHOD_POST}) 148 public Response createFile ( 149 @HTTPAuthenticationParameter(required = false) AuthenticationParameter authenticatedUser, 150 @HTTPMethodParameter(name = service.tut.pori.tasks.Definitions.PARAMETER_BACKEND_ID) LongParameter backendId, 151 @HTTPMethodParameter(name = InputStreamParameter.PARAMETER_DEFAULT_NAME, bodyParameter = true) InputStreamParameter file 152 ) 153 { 154 FileDetailsList list = new FileDetailsList(); 155 FileDetails details = new FileDetails(); 156 details.setGUID(SensorsReferenceCore.createFile(authenticatedUser.getUserIdentity(), backendId.getValue(), file.getValue())); 157 list.addFile(details); 158 return new Response(list); 159 } 160}