/* * Copyright (c) 2010, SQL Power Group Inc. * * This file is part of SQL Power Library. * * SQL Power Library is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * SQL Power Library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package ca.sqlpower.enterprise; import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import java.text.ParseException; import java.util.ArrayList; import java.util.List; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.CookieStore; import org.apache.http.client.HttpClient; import org.apache.http.client.ResponseHandler; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.entity.mime.MultipartEntity; import org.apache.http.entity.mime.content.ContentBody; import org.apache.http.entity.mime.content.FileBody; import org.apache.http.entity.mime.content.StringBody; import org.apache.http.impl.client.DefaultHttpClient; import org.apache.http.params.BasicHttpParams; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.springframework.security.AccessDeniedException; import ca.sqlpower.dao.SPPersistenceException; import ca.sqlpower.dao.json.SPJSONMessageDecoder; import ca.sqlpower.enterprise.client.ProjectLocation; import ca.sqlpower.enterprise.client.SPServerInfo; import ca.sqlpower.util.UserPrompter.UserPromptOptions; import ca.sqlpower.util.UserPrompter.UserPromptResponse; import ca.sqlpower.util.UserPrompterFactory; import ca.sqlpower.util.UserPrompterFactory.UserPromptType; /** * This class contains static methods mainly for posting different things to the server using the resources. * Any method in this class that requires a cookieStore should be called from {programName}ClientSideSession. * That is where the cookieStore comes from. */ public class ClientSideSessionUtils { /** * All requests to the server will contain this tag after the enterprise * server name (which is normally architect-enterprise). */ public static final String REST_TAG = "rest"; /** * The UUID of the system workspace. */ public static final String SYSTEM_UUID = "system"; public static HttpClient createHttpClient(SPServerInfo serviceInfo, CookieStore cookieStore) { return createHttpClient(serviceInfo.getServerAddress(), serviceInfo.getUsername(), serviceInfo.getPassword(), cookieStore); } public static HttpClient createHttpClient(String host, String username, String password, CookieStore cookieStore) { HttpParams params = new BasicHttpParams(); HttpConnectionParams.setConnectionTimeout(params, 2000); DefaultHttpClient httpClient = new DefaultHttpClient(params); httpClient.setCookieStore(cookieStore); httpClient.getCredentialsProvider().setCredentials( new AuthScope(host, AuthScope.ANY_PORT), new UsernamePasswordCredentials(username, password)); return httpClient; } public static ProjectLocation createNewServerSession(SPServerInfo serviceInfo, String name, CookieStore cookieStore, UserPrompterFactory userPrompterFactory) throws URISyntaxException, ClientProtocolException, IOException, JSONException { HttpClient httpClient = ClientSideSessionUtils.createHttpClient(serviceInfo, cookieStore); try { HttpUriRequest request = new HttpGet(getServerURI(serviceInfo, "/" + REST_TAG + "/jcr/projects/new", "name=" + name)); JSONMessage message = httpClient.execute(request, new JSONResponseHandler()); JSONObject response = new JSONObject(message.getBody()); return new ProjectLocation( response.getString("uuid"), response.getString("name"), serviceInfo); } catch (AccessDeniedException e) { userPrompterFactory.createUserPrompter("You do not have sufficient privileges to create a new workspace.", UserPromptType.MESSAGE, UserPromptOptions.OK, UserPromptResponse.OK, "OK", "OK").promptUser(""); return null; } finally { httpClient.getConnectionManager().shutdown(); } } public static URI getServerURI(SPServerInfo serviceInfo, String contextRelativePath) throws URISyntaxException { return getServerURI(serviceInfo, contextRelativePath, null); } public static URI getServerURI(SPServerInfo serviceInfo, String contextRelativePath, String query) throws URISyntaxException { String contextPath = serviceInfo.getPath(); URI serverURI = new URI(serviceInfo.getScheme(), null, serviceInfo.getServerAddress(), serviceInfo.getPort(), contextPath + contextRelativePath, query, null); return serverURI; } public static List<TransactionInformation> decodeJSONRevisionList(String json) throws JSONException, ParseException { JSONArray jsonArray = new JSONArray(json); List<TransactionInformation> transactions = new ArrayList<TransactionInformation>(); for (int i = 0; i < jsonArray.length(); i++) { JSONObject jsonItem = jsonArray.getJSONObject(i); TransactionInformation transaction = new TransactionInformation( jsonItem.getLong("number"), jsonItem.getLong("time"), jsonItem.getString("author"), jsonItem.getString("description"), jsonItem.getString("simpleDescription")); transactions.add(transaction); } return transactions; } public static void deleteServerWorkspace(ProjectLocation projectLocation, CookieStore cookieStore, UserPrompterFactory userPrompterFactory) throws URISyntaxException, ClientProtocolException, IOException { SPServerInfo serviceInfo = projectLocation.getServiceInfo(); HttpClient httpClient = ClientSideSessionUtils.createHttpClient(serviceInfo, cookieStore); try { executeServerRequest(httpClient, projectLocation.getServiceInfo(), "/" + ClientSideSessionUtils.REST_TAG + "/jcr/" + projectLocation.getUUID() + "/delete", new JSONResponseHandler()); } catch (AccessDeniedException e) { userPrompterFactory.createUserPrompter("You do not have sufficient privileges to delete the selected workspace.", UserPromptType.MESSAGE, UserPromptOptions.OK, UserPromptResponse.OK, "OK", "OK").promptUser(""); } finally { httpClient.getConnectionManager().shutdown(); } } public static <T> T executeServerRequest(HttpClient httpClient, SPServerInfo serviceInfo, String contextRelativePath, ResponseHandler<T> responseHandler)throws IOException, URISyntaxException { return executeServerRequest(httpClient, serviceInfo, contextRelativePath, null, responseHandler); } public static <T> T executeServerRequest(HttpClient httpClient, SPServerInfo serviceInfo, String contextRelativePath, String query, ResponseHandler<T> responseHandler) throws IOException, URISyntaxException { HttpUriRequest request = new HttpGet(getServerURI(serviceInfo, contextRelativePath, query)); return httpClient.execute(request, responseHandler); } public static List<ProjectLocation> getWorkspaceNames(SPServerInfo serviceInfo, CookieStore cookieStore, UserPrompterFactory upf) throws IOException, URISyntaxException, JSONException { HttpClient httpClient = ClientSideSessionUtils.createHttpClient(serviceInfo, cookieStore); try { HttpUriRequest request = new HttpGet(getServerURI(serviceInfo, "/" + ClientSideSessionUtils.REST_TAG + "/jcr/projects")); JSONMessage message = httpClient.execute(request, new JSONResponseHandler()); if (message.getStatusCode() == 412) { //precondition failed upf.createUserPrompter(message.getBody(), UserPromptType.MESSAGE, UserPromptOptions.OK, UserPromptResponse.OK, null, "OK").promptUser(); } List<ProjectLocation> workspaces = new ArrayList<ProjectLocation>(); JSONArray response = new JSONArray(message.getBody()); for (int i = 0; i < response.length(); i++) { JSONObject workspace = (JSONObject) response.get(i); workspaces.add(new ProjectLocation( workspace.getString("uuid"), workspace.getString("name"), serviceInfo)); } return workspaces; } catch (AccessDeniedException e) { throw e; } finally { httpClient.getConnectionManager().shutdown(); } } /** * Requests the server for persist calls from version 0 to the given revision * of the given project, and persists them to the given decoder. * * @param projectLocation * @param revisionNo Must be greater than zero, and no greater than the current revision number * @param decoder * @throws IOException * @throws URISyntaxException * @throws SPPersistenceException * @throws IllegalArgumentException Thrown if the server rejects the given revisionNo */ public static void persistRevisionFromServer(ProjectLocation projectLocation, int revisionNo, SPJSONMessageDecoder decoder, CookieStore cookieStore) throws IOException, URISyntaxException, SPPersistenceException, IllegalArgumentException { SPServerInfo serviceInfo = projectLocation.getServiceInfo(); HttpClient httpClient = ClientSideSessionUtils.createHttpClient(serviceInfo, cookieStore); try { JSONMessage response = ClientSideSessionUtils.executeServerRequest(httpClient, serviceInfo, "/" + ClientSideSessionUtils.REST_TAG + "/project/" + projectLocation.getUUID() + "/" + revisionNo, new JSONResponseHandler()); if (response.isSuccessful()) { decoder.decode(response.getBody()); } else { throw new IllegalArgumentException("The server rejected the revision number " + "(it must be greater than 0, and no greater than the current revision number)"); } } finally { httpClient.getConnectionManager().shutdown(); } } /** * This method reverts the server workspace specified by the given project location * to the specified revision number. * * All sessions should automatically update to the reverted revision due to their Updater. * * @returns The new global revision number, right after the reversion, or -1 if the server did not revert. * @throws IOException * @throws URISyntaxException * @throws JSONException */ public static int revertServerWorkspace(ProjectLocation projectLocation, int revisionNo, CookieStore cookieStore) throws IOException, URISyntaxException, JSONException { SPServerInfo serviceInfo = projectLocation.getServiceInfo(); HttpClient httpClient = ClientSideSessionUtils.createHttpClient(serviceInfo, cookieStore); try { JSONMessage message = ClientSideSessionUtils.executeServerRequest(httpClient, projectLocation.getServiceInfo(), "/" + ClientSideSessionUtils.REST_TAG + "/project/" + projectLocation.getUUID() + "/revert", "revisionNo=" + revisionNo, new JSONResponseHandler()); if (message.isSuccessful()) { return new JSONObject(message.getBody()).getInt("currentRevision"); } else { return -1; } } finally { httpClient.getConnectionManager().shutdown(); } } public static ProjectLocation uploadProject(SPServerInfo serviceInfo, String name, File project, UserPrompterFactory session, CookieStore cookieStore) throws URISyntaxException, ClientProtocolException, IOException, JSONException { HttpClient httpClient = ClientSideSessionUtils.createHttpClient(serviceInfo, cookieStore); try { MultipartEntity entity = new MultipartEntity(); ContentBody fileBody = new FileBody(project); ContentBody nameBody = new StringBody(name); entity.addPart("file", fileBody); entity.addPart("name", nameBody); HttpPost request = new HttpPost(ClientSideSessionUtils.getServerURI(serviceInfo, "/" + ClientSideSessionUtils.REST_TAG + "/jcr", "name=" + name)); request.setEntity(entity); JSONMessage message = httpClient.execute(request, new JSONResponseHandler()); JSONObject response = new JSONObject(message.getBody()); return new ProjectLocation( response.getString("uuid"), response.getString("name"), serviceInfo); } catch (AccessDeniedException e) { session.createUserPrompter("You do not have sufficient privileges to create a new workspace.", UserPromptType.MESSAGE, UserPromptOptions.OK, UserPromptResponse.OK, "OK", "OK").promptUser(""); return null; } finally { httpClient.getConnectionManager().shutdown(); } } }