/*
* Copyright (c) 2012. Piraso Alvin R. de Leon. All Rights Reserved.
*
* See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The Piraso licenses this file to You 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.piraso.server.spring.web;
import org.apache.commons.lang.Validate;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.piraso.api.JacksonUtils;
import org.piraso.api.entry.Entry;
import org.piraso.api.entry.RawEntry;
import org.piraso.server.PirasoContextIDGenerator;
import org.piraso.server.service.*;
import org.piraso.web.base.PirasoHttpServletRequest;
import org.piraso.web.base.PirasoHttpServletResponse;
import org.springframework.web.HttpRequestHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;
import static org.piraso.api.PirasoConstants.*;
/**
* Entry point for requesting a starting and stopping log monitor activity.
*/
public class PirasoServlet implements HttpRequestHandler {
/**
* final class logging instance.
*/
private static final Log LOG = LogFactory.getLog(PirasoServlet.class);
public static final long DEFAULT_STOP_TIMEOUT = 10000l;
private Integer maxQueueForceKillSize;
private Long maxIdleTimeout;
private Long stopTimeout = DEFAULT_STOP_TIMEOUT;
private String version;
public void setVersion(String version) {
this.version = version;
}
public void setMaxIdleTimeout(Long maxIdleTimeout) {
this.maxIdleTimeout = maxIdleTimeout;
}
public void setMaxQueueForceKillSize(Integer maxQueueForceKillSize) {
this.maxQueueForceKillSize = maxQueueForceKillSize;
}
public void setStopTimeout(Long stopTimeout) {
this.stopTimeout = stopTimeout;
}
public UserRegistry getRegistry() {
return (UserRegistry) LoggerRegistrySingleton.INSTANCE.getRegistry();
}
private void writeResponse(HttpServletResponse response, String contentType, String str) throws IOException {
PrintWriter out = response.getWriter();
try {
response.setContentType(contentType);
response.setCharacterEncoding(ENCODING_UTF_8);
out.write(str);
out.flush();
} finally {
out.close();
}
}
public void handleRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if(request.getParameter(SERVICE_PARAMETER) == null) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "Request Parameter 'service' is required.");
return;
}
User user = getRegistry().createOrGetUser(new PirasoHttpServletRequest(request));
if(SERVICE_GET_REGISTRY_PARAMETER_VALUE.equals(request.getParameter(SERVICE_PARAMETER))) {
retrieveRegistry(response);
} else if(SERVICE_LOG_PARAMETER_VALUE.equals(request.getParameter(SERVICE_PARAMETER))) {
log(request);
writeResponse(response, PLAIN_CONTENT_TYPE, "OK");
} else if(SERVICE_REQUEST_ID_PARAMETER_VALUE.equals(request.getParameter(SERVICE_PARAMETER))) {
writeResponse(response, PLAIN_CONTENT_TYPE, String.valueOf(PirasoContextIDGenerator.INSTANCE.next()));
} else if(SERVICE_START_PARAMETER_VALUE.equals(request.getParameter(SERVICE_PARAMETER))) {
startLoggerService(request, response, user);
} else if(SERVICE_STOP_PARAMETER_VALUE.equals(request.getParameter(SERVICE_PARAMETER))) {
stopService(response, user);
writeResponse(response, PLAIN_CONTENT_TYPE, "OK");
} else if(SERVICE_TEST_PARAMETER_VALUE.equals(request.getParameter(SERVICE_PARAMETER))) {
writeResponse(response, JSON_CONTENT_TYPE, String.format("{\"status\":\"%s\", \"version\":\"%s\", \"bridgeSupported\": true}", STATUS_OK, version));
} else {
response.sendError(HttpServletResponse.SC_BAD_REQUEST,
String.format("Request Parameter 'service' with value '%s' is invalid.",
request.getParameter(SERVICE_PARAMETER)));
}
}
private void retrieveRegistry(HttpServletResponse response) throws IOException {
BridgeRegistry bridgeRegistry = new BridgeRegistry();
for(Map.Entry<User, ResponseLoggerService> entry : getRegistry().getUserLoggerMap().entrySet()) {
bridgeRegistry.addLogger(new BridgeLogger(entry.getValue()));
}
writeResponse(response, JSON_CONTENT_TYPE, JacksonUtils.MAPPER.writeValueAsString(bridgeRegistry));
}
private void log(HttpServletRequest request) throws IOException {
String userContent = request.getParameter(USER_PARAMETER);
String requestId = request.getParameter(ENTRY_REQUEST_ID_PARAMETER);
String entryContent = request.getParameter(ENTRY_PARAMETER);
String entryClassName = request.getParameter(ENTRY_CLASS_NAME_PARAMETER);
Validate.notNull(userContent, "userContent should not be null.");
User user = JacksonUtils.MAPPER.readValue(userContent, User.class);
ResponseLoggerService service = getRegistry().getLogger(user);
if(service != null && service.isAlive()) {
Validate.notNull(entryContent, "entryContent should not be null.");
Validate.notNull(entryClassName, "entryClassName should not be null.");
Entry entry = new RawEntry(Long.valueOf(requestId), entryClassName, entryContent);
service.log(entry);
}
}
private void stopService(HttpServletResponse response, User user) throws IOException {
ResponseLoggerService service = getRegistry().getLogger(user);
if(service == null) {
response.sendError(HttpServletResponse.SC_NOT_FOUND, String.format("Service for user '%s' not found.", user.toString()));
return;
}
if(!service.isAlive()) {
response.sendError(HttpServletResponse.SC_CONFLICT, String.format("Service for user '%s' not active.", user.toString()));
getRegistry().removeUser(user);
return;
}
try {
// gracefully stop the service
service.stopAndWait(stopTimeout);
if(service.isAlive()) {
response.sendError(HttpServletResponse.SC_REQUEST_TIMEOUT, String.format("Service for user '%s' stop timeout.", user.toString()));
}
} catch (InterruptedException ignored) {}
}
private void startLoggerService(HttpServletRequest request, HttpServletResponse response, User user) throws IOException, ServletException {
ResponseLoggerServiceImpl service = new ResponseLoggerServiceImpl(
user,
new PirasoHttpServletRequest(request),
new PirasoHttpServletResponse(response)
);
if(maxQueueForceKillSize != null) {
service.setMaxQueueForceKillSize(maxQueueForceKillSize);
}
if(maxIdleTimeout != null) {
service.setMaxIdleTimeout(maxIdleTimeout);
}
try {
getRegistry().associate(user, service);
service.start();
} catch (Exception e) {
LOG.warn(e.getMessage(), e);
} finally {
getRegistry().removeUser(user);
}
}
}