Skip to content
Snippets Groups Projects
Commit 833b0a4a authored by Brian Major's avatar Brian Major
Browse files

ac2 - Added SyncOutput to wrap the http servlet response

parent 4c0353bc
No related branches found
No related tags found
No related merge requests found
Showing
with 215 additions and 87 deletions
/*
************************************************************************
******************* CANADIAN ASTRONOMY DATA CENTRE *******************
************** CENTRE CANADIEN DE DONNÉES ASTRONOMIQUES **************
*
* (c) 2011. (c) 2011.
* Government of Canada Gouvernement du Canada
* National Research Council Conseil national de recherches
* Ottawa, Canada, K1A 0R6 Ottawa, Canada, K1A 0R6
* All rights reserved Tous droits réservés
*
* NRC disclaims any warranties, Le CNRC dénie toute garantie
* expressed, implied, or énoncée, implicite ou légale,
* statutory, of any kind with de quelque nature que ce
* respect to the software, soit, concernant le logiciel,
* including without limitation y compris sans restriction
* any warranty of merchantability toute garantie de valeur
* or fitness for a particular marchande ou de pertinence
* purpose. NRC shall not be pour un usage particulier.
* liable in any event for any Le CNRC ne pourra en aucun cas
* damages, whether direct or être tenu responsable de tout
* indirect, special or general, dommage, direct ou indirect,
* consequential or incidental, particulier ou général,
* arising from the use of the accessoire ou fortuit, résultant
* software. Neither the name de l'utilisation du logiciel. Ni
* of the National Research le nom du Conseil National de
* Council of Canada nor the Recherches du Canada ni les noms
* names of its contributors may de ses participants ne peuvent
* be used to endorse or promote être utilisés pour approuver ou
* products derived from this promouvoir les produits dérivés
* software without specific prior de ce logiciel sans autorisation
* written permission. préalable et particulière
* par écrit.
*
* This file is part of the Ce fichier fait partie du projet
* OpenCADC project. OpenCADC.
*
* OpenCADC is free software: OpenCADC est un logiciel libre ;
* you can redistribute it and/or vous pouvez le redistribuer ou le
* modify it under the terms of modifier suivant les termes de
* the GNU Affero General Public la “GNU Affero General Public
* License as published by the License” telle que publiée
* Free Software Foundation, par la Free Software Foundation
* either version 3 of the : soit la version 3 de cette
* License, or (at your option) licence, soit (à votre gré)
* any later version. toute version ultérieure.
*
* OpenCADC is distributed in the OpenCADC est distribué
* hope that it will be useful, dans l’espoir qu’il vous
* but WITHOUT ANY WARRANTY; sera utile, mais SANS AUCUNE
* without even the implied GARANTIE : sans même la garantie
* warranty of MERCHANTABILITY implicite de COMMERCIALISABILITÉ
* or FITNESS FOR A PARTICULAR ni d’ADÉQUATION À UN OBJECTIF
* PURPOSE. See the GNU Affero PARTICULIER. Consultez la Licence
* General Public License for Générale Publique GNU Affero
* more details. pour plus de détails.
*
* You should have received Vous devriez avoir reçu une
* a copy of the GNU Affero copie de la Licence Générale
* General Public License along Publique GNU Affero avec
* with OpenCADC. If not, see OpenCADC ; si ce n’est
* <http://www.gnu.org/licenses/>. pas le cas, consultez :
* <http://www.gnu.org/licenses/>.
*
* $Revision: 5 $
*
************************************************************************
*/
package ca.nrc.cadc.ac.server.web;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
/**
*
* @author majorb
*/
public class SyncOutput
{
private static final Logger log = Logger.getLogger(SyncOutput.class);
protected HttpServletResponse response;
protected PrintWriter writer;
public SyncOutput(HttpServletResponse response)
{
this.response = response;
}
public boolean isOpen()
{
return (writer != null);
}
public void setCode(int code)
{
if (writer != null)
return;
response.setStatus(code);
}
public void setHeader(String key, Object value)
{
if (writer != null)
return;
if (value == null)
response.setHeader(key, null);
else
response.setHeader(key, value.toString());
}
public PrintWriter getWriter()
throws IOException
{
if (writer == null)
{
log.debug("opening writer");
writer = response.getWriter();
}
return writer;
}
}
......@@ -89,6 +89,7 @@ import ca.nrc.cadc.ac.UserNotFoundException;
import ca.nrc.cadc.ac.server.GroupPersistence;
import ca.nrc.cadc.ac.server.PluginFactory;
import ca.nrc.cadc.ac.server.UserPersistence;
import ca.nrc.cadc.ac.server.web.SyncOutput;
import ca.nrc.cadc.net.TransientException;
public abstract class AbstractGroupAction implements PrivilegedExceptionAction<Object>
......@@ -96,7 +97,7 @@ public abstract class AbstractGroupAction implements PrivilegedExceptionAction<O
private static final Logger log = Logger.getLogger(AbstractGroupAction.class);
protected GroupLogInfo logInfo;
protected HttpServletRequest request;
protected HttpServletResponse response;
protected SyncOutput syncOut;
public AbstractGroupAction()
{
......@@ -114,9 +115,9 @@ public abstract class AbstractGroupAction implements PrivilegedExceptionAction<O
this.request = request;
}
void setHttpServletResponse(HttpServletResponse response)
void setSyncOut(SyncOutput syncOut)
{
this.response = response;
this.syncOut = syncOut;
}
public Object run() throws PrivilegedActionException
......@@ -206,26 +207,19 @@ public abstract class AbstractGroupAction implements PrivilegedExceptionAction<O
private void sendError(int responseCode, String message)
{
if (!this.response.isCommitted())
syncOut.setHeader("Content-Type", "text/plain");
if (message != null)
{
this.response.setContentType("text/plain");
if (message != null)
try
{
try
{
this.response.getWriter().write(message);
}
catch (IOException e)
{
log.warn("Could not write error message to output stream");
}
syncOut.getWriter() .write(message);
}
catch (IOException e)
{
log.warn("Could not write error message to output stream");
}
this.response.setStatus(responseCode);
}
else
{
log.warn("Could not send error " + responseCode + " (" + message + ") because the response is already committed.");
}
syncOut.setCode(responseCode);
}
<T extends Principal> GroupPersistence<T> getGroupPersistence()
......
......@@ -94,9 +94,9 @@ public class CreateGroupAction extends AbstractGroupAction
GroupReader groupReader = new GroupReader();
Group group = groupReader.read(this.inputStream);
Group newGroup = groupPersistence.addGroup(group);
this.response.setContentType("application/xml");
syncOut.setHeader("Content-Type", "application/xml");
GroupWriter groupWriter = new GroupWriter();
groupWriter.write(newGroup, this.response.getOutputStream());
groupWriter.write(newGroup, syncOut.getWriter());
List<String> addedMembers = null;
if ((newGroup.getUserMembers().size() > 0) || (newGroup.getGroupMembers().size() > 0))
......
......@@ -85,10 +85,9 @@ public class GetGroupAction extends AbstractGroupAction
{
GroupPersistence groupPersistence = getGroupPersistence();
Group group = groupPersistence.getGroup(this.groupName);
this.response.setContentType("application/xml");
syncOut.setHeader("Content-Type", "application/xml");
GroupWriter groupWriter = new GroupWriter();
groupWriter.write(group, this.response.getOutputStream());
groupWriter.write(group, syncOut.getWriter());
}
}
......@@ -91,9 +91,9 @@ public class GetGroupNamesAction extends AbstractGroupAction
GroupPersistence groupPersistence = getGroupPersistence();
Collection<String> groups = groupPersistence.getGroupNames();
log.debug("Found " + groups.size() + " group names");
response.setContentType("text/plain");
syncOut.setHeader("Content-Type", "text/plain");
log.debug("Set content-type to text/plain");
Writer writer = response.getWriter();
Writer writer = syncOut.getWriter();
boolean start = true;
for (final String group : groups)
{
......
......@@ -78,6 +78,7 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.log4j.Logger;
import ca.nrc.cadc.ac.server.web.SyncOutput;
import ca.nrc.cadc.auth.AuthenticationUtil;
import ca.nrc.cadc.util.StringUtil;
......@@ -109,7 +110,8 @@ public class GroupServlet extends HttpServlet
action.setLogInfo(logInfo);
action.setHttpServletRequest(request);
action.setHttpServletResponse(response);
SyncOutput syncOut = new SyncOutput(response);
action.setSyncOut(syncOut);
try
{
......
......@@ -133,7 +133,8 @@ public class ModifyGroupAction extends AbstractGroupAction
}
logGroupInfo(group.getID(), deletedMembers, addedMembers);
this.response.sendRedirect(request);
syncOut.setHeader("Location", "/" + group.getID());
syncOut.setCode(303);
}
}
......@@ -78,6 +78,7 @@ import ca.nrc.cadc.ac.json.JsonUserRequestReader;
import ca.nrc.cadc.ac.json.JsonUserWriter;
import ca.nrc.cadc.ac.server.PluginFactory;
import ca.nrc.cadc.ac.server.UserPersistence;
import ca.nrc.cadc.ac.server.web.SyncOutput;
import ca.nrc.cadc.auth.AuthenticationUtil;
import ca.nrc.cadc.ac.xml.UserListWriter;
import ca.nrc.cadc.ac.xml.UserReader;
......@@ -104,7 +105,8 @@ public abstract class AbstractUserAction implements PrivilegedExceptionAction<Ob
static final String JSON_CONTENT_TYPE = "application/json";
protected UserLogInfo logInfo;
protected HttpServletResponse response;
protected SyncOutput syncOut;
protected String acceptedContentType = DEFAULT_CONTENT_TYPE;
AbstractUserAction()
......@@ -118,9 +120,9 @@ public abstract class AbstractUserAction implements PrivilegedExceptionAction<Ob
this.logInfo = logInfo;
}
public void setResponse(HttpServletResponse response)
public void setSyncOut(SyncOutput syncOut)
{
this.response = response;
this.syncOut = syncOut;
}
public Object run() throws IOException
......@@ -182,21 +184,20 @@ public abstract class AbstractUserAction implements PrivilegedExceptionAction<Ob
}
private void sendError(int responseCode, String message)
throws IOException
{
if (!this.response.isCommitted())
syncOut.setHeader("Content-Type", "text/plain");
if (message != null)
{
this.response.setContentType("text/plain");
if (message != null)
try
{
this.response.getWriter().write(message);
syncOut.getWriter() .write(message);
}
catch (IOException e)
{
log.warn("Could not write error message to output stream");
}
this.response.setStatus(responseCode);
}
else
{
log.warn("Could not send error " + responseCode + " (" + message + ") because the response is already committed.");
}
syncOut.setCode(responseCode);
}
@SuppressWarnings("unchecked")
......@@ -260,7 +261,7 @@ public abstract class AbstractUserAction implements PrivilegedExceptionAction<Ob
protected final User<Principal> readUser(final InputStream inputStream)
throws IOException
{
response.setContentType(acceptedContentType);
syncOut.setHeader("Content-Type", acceptedContentType);
final User<Principal> user;
if (acceptedContentType.equals(DEFAULT_CONTENT_TYPE))
......@@ -292,8 +293,8 @@ public abstract class AbstractUserAction implements PrivilegedExceptionAction<Ob
protected final <T extends Principal> void writeUser(final User<T> user)
throws IOException
{
response.setContentType(acceptedContentType);
final Writer writer = response.getWriter();
syncOut.setHeader("Content-Type", acceptedContentType);
final Writer writer = syncOut.getWriter();
if (acceptedContentType.equals(DEFAULT_CONTENT_TYPE))
{
......@@ -315,8 +316,8 @@ public abstract class AbstractUserAction implements PrivilegedExceptionAction<Ob
protected final void writeUsers(final Map<String, PersonalDetails> users)
throws IOException
{
response.setContentType(acceptedContentType);
final Writer writer = response.getWriter();
syncOut.setHeader("Content-Type", acceptedContentType);
final Writer writer = syncOut.getWriter();
if (acceptedContentType.equals(DEFAULT_CONTENT_TYPE))
{
......@@ -350,8 +351,8 @@ public abstract class AbstractUserAction implements PrivilegedExceptionAction<Ob
throw new IllegalStateException("No identities found.");
}
response.setStatus(HttpServletResponse.SC_OK);
final String redirectURL = "/" + id + "?idType=" + idType;
response.setHeader("Location", redirectURL);
syncOut.setHeader("Location", redirectURL);
syncOut.setCode(303);
}
}
......@@ -95,7 +95,7 @@ public class CreateUserAction extends AbstractUserAction
final UserRequest<Principal> userRequest = readUserRequest(this.inputStream);
final User<Principal> newUser = userPersistence.addUser(userRequest);
response.setStatus(HttpServletResponse.SC_CREATED);
syncOut.setCode(201);
logUserInfo(newUser.getUserID().getName());
}
......
......@@ -79,6 +79,7 @@ import javax.servlet.http.HttpServletResponse;
import ca.nrc.cadc.util.StringUtil;
import org.apache.log4j.Logger;
import ca.nrc.cadc.ac.server.web.SyncOutput;
import ca.nrc.cadc.auth.AuthenticationUtil;
public class UserServlet extends HttpServlet
......@@ -103,9 +104,10 @@ public class UserServlet extends HttpServlet
logInfo.setSubject(subject);
AbstractUserAction action = factory.createAction(request);
SyncOutput syncOut = new SyncOutput(response);
action.setLogInfo(logInfo);
action.setResponse(response);
action.setSyncOut(syncOut);
action.setAcceptedContentType(getAcceptedContentType(request));
try
......
......@@ -70,6 +70,7 @@ package ca.nrc.cadc.ac.server.web.users;
import ca.nrc.cadc.ac.User;
import ca.nrc.cadc.ac.json.JsonUserWriter;
import ca.nrc.cadc.ac.server.UserPersistence;
import ca.nrc.cadc.ac.server.web.SyncOutput;
import ca.nrc.cadc.ac.xml.UserWriter;
import ca.nrc.cadc.auth.HttpPrincipal;
import org.junit.Test;
......@@ -87,8 +88,8 @@ public class GetUserActionTest
@Test
public void writeUserXML() throws Exception
{
final HttpServletResponse mockResponse =
createMock(HttpServletResponse.class);
final SyncOutput mockSyncOut =
createMock(SyncOutput.class);
final UserPersistence<HttpPrincipal> mockUserPersistence =
createMock(UserPersistence.class);
final HttpPrincipal userID = new HttpPrincipal("CADCtest");
......@@ -107,13 +108,13 @@ public class GetUserActionTest
final PrintWriter printWriter = new PrintWriter(writer);
expect(mockUserPersistence.getUser(userID)).andReturn(user).once();
expect(mockResponse.getWriter()).andReturn(printWriter).once();
mockResponse.setContentType("text/xml");
expect(mockSyncOut.getWriter()).andReturn(printWriter).once();
mockSyncOut.setHeader("Content-Type", "text/xml");
expectLastCall().once();
replay(mockResponse, mockUserPersistence);
replay(mockSyncOut, mockUserPersistence);
testSubject.setResponse(mockResponse);
testSubject.setSyncOut(mockSyncOut);
testSubject.doAction();
StringBuilder sb = new StringBuilder();
......@@ -121,14 +122,14 @@ public class GetUserActionTest
userWriter.write(user, sb);
assertEquals(sb.toString(), writer.toString());
verify(mockResponse, mockUserPersistence);
verify(mockSyncOut, mockUserPersistence);
}
@Test
public void writeUserJSON() throws Exception
{
final HttpServletResponse mockResponse =
createMock(HttpServletResponse.class);
final SyncOutput mockSyncOut =
createMock(SyncOutput.class);
final UserPersistence<HttpPrincipal> mockUserPersistence =
createMock(UserPersistence.class);
final HttpPrincipal userID = new HttpPrincipal("CADCtest");
......@@ -149,12 +150,12 @@ public class GetUserActionTest
final PrintWriter printWriter = new PrintWriter(writer);
expect(mockUserPersistence.getUser(userID)).andReturn(user).once();
expect(mockResponse.getWriter()).andReturn(printWriter).once();
mockResponse.setContentType("application/json");
expect(mockSyncOut.getWriter()).andReturn(printWriter).once();
mockSyncOut.setHeader("Content-Type", "application/json");
expectLastCall().once();
replay(mockResponse, mockUserPersistence);
testSubject.setResponse(mockResponse);
replay(mockSyncOut, mockUserPersistence);
testSubject.setSyncOut(mockSyncOut);
UserLogInfo logInfo = createMock(UserLogInfo.class);
testSubject.setLogInfo(logInfo);
testSubject.doAction();
......@@ -164,6 +165,6 @@ public class GetUserActionTest
userWriter.write(user, sb);
assertEquals(sb.toString(), writer.toString());
verify(mockResponse, mockUserPersistence);
verify(mockSyncOut, mockUserPersistence);
}
}
......@@ -72,6 +72,7 @@ package ca.nrc.cadc.ac.server.web.users;
import ca.nrc.cadc.ac.PersonalDetails;
import ca.nrc.cadc.ac.json.JsonUserListWriter;
import ca.nrc.cadc.ac.server.UserPersistence;
import ca.nrc.cadc.ac.server.web.SyncOutput;
import ca.nrc.cadc.ac.xml.UserListWriter;
import ca.nrc.cadc.auth.HttpPrincipal;
import org.apache.log4j.Level;
......@@ -110,8 +111,8 @@ public class GetUserListActionTest
@SuppressWarnings("unchecked")
public void testWriteUsersJSON() throws Exception
{
final HttpServletResponse mockResponse =
createMock(HttpServletResponse.class);
final SyncOutput mockSyncOut =
createMock(SyncOutput.class);
final UserPersistence<HttpPrincipal> mockUserPersistence =
createMock(UserPersistence.class);
final Map<String, PersonalDetails> userEntries =
......@@ -139,12 +140,12 @@ public class GetUserListActionTest
expect(mockUserPersistence.getUsers()).andReturn(
userEntries).once();
expect(mockResponse.getWriter()).andReturn(actualPrintWriter).once();
mockResponse.setContentType("application/json");
expect(mockSyncOut.getWriter()).andReturn(actualPrintWriter).once();
mockSyncOut.setHeader("Content-Type", "application/json");
expectLastCall().once();
replay(mockResponse, mockUserPersistence);
testSubject.setResponse(mockResponse);
replay(mockSyncOut, mockUserPersistence);
testSubject.setSyncOut(mockSyncOut);
UserLogInfo logInfo = createMock(UserLogInfo.class);
testSubject.setLogInfo(logInfo);
testSubject.doAction();
......@@ -155,15 +156,15 @@ public class GetUserListActionTest
userListWriter.write(userEntries, expectedPrintWriter);
JSONAssert.assertEquals(expectedWriter.toString(), actualWriter.toString(), false);
verify(mockResponse, mockUserPersistence);
verify(mockSyncOut, mockUserPersistence);
}
@Test
@SuppressWarnings("unchecked")
public void testWriteUsersXML() throws Exception
{
final HttpServletResponse mockResponse =
createMock(HttpServletResponse.class);
final SyncOutput mockSyncOut =
createMock(SyncOutput.class);
final UserPersistence<HttpPrincipal> mockUserPersistence =
createMock(UserPersistence.class);
final Map<String, PersonalDetails> userEntries =
......@@ -189,12 +190,12 @@ public class GetUserListActionTest
expect(mockUserPersistence.getUsers()).andReturn(
userEntries).once();
expect(mockResponse.getWriter()).andReturn(actualPrintWriter).once();
mockResponse.setContentType("text/xml");
expect(mockSyncOut.getWriter()).andReturn(actualPrintWriter).once();
mockSyncOut.setHeader("Content-Type", "text/xml");
expectLastCall().once();
replay(mockResponse, mockUserPersistence);
testSubject.setResponse(mockResponse);
replay(mockSyncOut, mockUserPersistence);
testSubject.setSyncOut(mockSyncOut);
UserLogInfo logInfo = createMock(UserLogInfo.class);
testSubject.setLogInfo(logInfo);
testSubject.doAction();
......@@ -205,6 +206,6 @@ public class GetUserListActionTest
userListWriter.write(userEntries, expectedPrintWriter);
assertEquals("Wrong XML", expectedWriter.toString(), actualWriter.toString());
verify(mockResponse, mockUserPersistence);
verify(mockSyncOut, mockUserPersistence);
}
}
......@@ -72,6 +72,7 @@ import ca.nrc.cadc.ac.PersonalDetails;
import ca.nrc.cadc.ac.User;
import ca.nrc.cadc.ac.json.JsonUserWriter;
import ca.nrc.cadc.ac.server.UserPersistence;
import ca.nrc.cadc.ac.server.web.SyncOutput;
import ca.nrc.cadc.auth.HttpPrincipal;
import org.junit.Test;
......@@ -120,8 +121,8 @@ public class ModifyUserActionTest
final HttpServletRequest mockRequest =
createMock(HttpServletRequest.class);
final HttpServletResponse mockResponse =
createMock(HttpServletResponse.class);
final SyncOutput mockSyncOut =
createMock(SyncOutput.class);
@SuppressWarnings("unchecked")
final UserPersistence<Principal> mockUserPersistence =
......@@ -133,17 +134,16 @@ public class ModifyUserActionTest
// expect(mockRequest.getRemoteAddr()).andReturn(requestURL).
// once();
mockResponse.setHeader("Location", "/CADCtest?idType=http");
mockSyncOut.setHeader("Location", "/CADCtest?idType=http");
expectLastCall().once();
mockResponse.setStatus(200);
mockSyncOut.setCode(303);
expectLastCall().once();
mockResponse.setContentType("application/json");
mockSyncOut.setHeader("Content-Type", "application/json");
expectLastCall().once();
replay(mockRequest, mockResponse, mockUserPersistence);
replay(mockRequest, mockSyncOut, mockUserPersistence);
final ModifyUserAction testSubject = new ModifyUserAction(inputStream)
{
......@@ -156,11 +156,11 @@ public class ModifyUserActionTest
};
testSubject.setAcceptedContentType("application/json");
testSubject.response = mockResponse;
testSubject.syncOut = mockSyncOut;
UserLogInfo logInfo = createMock(UserLogInfo.class);
testSubject.setLogInfo(logInfo);
testSubject.doAction();
verify(mockRequest, mockResponse, mockUserPersistence);
verify(mockRequest, mockSyncOut, mockUserPersistence);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment