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&amp;{@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}