001/* 002 * ModeShape (http://www.modeshape.org) 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 org.modeshape.jdbc.rest; 017 018import java.io.ByteArrayInputStream; 019import javax.jcr.query.Query; 020import org.modeshape.common.util.CheckArg; 021import org.modeshape.jdbc.JdbcI18n; 022 023/** 024 * A simple java client which communicates via a {@link JSONRestClient} to an existing ModeShape REST service and unmarshals the 025 * JSON objects into a custom POJO model. 026 * 027 * @author Horia Chiorean (hchiorea@redhat.com) 028 */ 029public final class ModeShapeRestClient { 030 031 private static final String NODE_TYPES_SEGMENT = "jcr:system/jcr:nodeTypes?depth=-1"; 032 private static final String ITEMS_METHOD = "items"; 033 private static final String QUERY_METHOD = "query"; 034 private static final String QUERY_PLAN_METHOD = "queryPlan"; 035 036 private final JSONRestClient jsonRestClient; 037 038 /** 039 * Creates a new REST client instance which will always use the given URL as the server connection 040 * 041 * @param repoUrl a {@code String} representing a connection to a ModeShape REST service in the format: 042 * [protocol]://[host]:[port]/[context]/[repository]/[workspace]. May not be {@code null} 043 * @param username a {@code String} representing the name of the user to use when authenticating with the above server. May be 044 * {@code null}, in which case no authentication will be performed. 045 * @param password a {@code String} the password of the above user, if used. May be {@code null} 046 */ 047 public ModeShapeRestClient( String repoUrl, 048 String username, 049 String password ) { 050 CheckArg.isNotNull(repoUrl, "repoUrl"); 051 this.jsonRestClient = new JSONRestClient(repoUrl, username, password); 052 } 053 054 /** 055 * Returns the URL this client uses to connect to the server. 056 * 057 * @return a {@code String}, never {@code null} 058 */ 059 public String serverUrl() { 060 return jsonRestClient.url(); 061 } 062 063 /** 064 * Returns a list with all the available repositories. 065 * 066 * @return a {@link Repositories} instance, never {@code null} 067 */ 068 public Repositories getRepositories() { 069 JSONRestClient.Response response = jsonRestClient.doGet(); 070 if (!response.isOK()) { 071 throw new RuntimeException(JdbcI18n.invalidServerResponse.text(jsonRestClient.url(), response.asString())); 072 } 073 return new Repositories(response.json()); 074 } 075 076 /** 077 * Returns a repository which has the given name or {@code null}. 078 * 079 * @param name the name of a repository; may not be null 080 * @return a {@link Repositories.Repository} instace or {@code null} 081 */ 082 public Repositories.Repository getRepository( String name ) { 083 JSONRestClient.Response response = jsonRestClient.doGet(); 084 if (!response.isOK()) { 085 throw new RuntimeException(JdbcI18n.invalidServerResponse.text(jsonRestClient.url(), response.asString())); 086 } 087 return new Repositories(response.json()).getRepository(name); 088 } 089 090 /** 091 * Returns all the workspaces for the named repository. 092 * 093 * @param repositoryName a {@code String} the name of a repository; may not be {@code null} 094 * @return a {@link Workspaces} instance; never {@code null} 095 */ 096 public Workspaces getWorkspaces( String repositoryName ) { 097 String url = jsonRestClient.appendToBaseURL(repositoryName); 098 JSONRestClient.Response response = jsonRestClient.doGet(url); 099 if (!response.isOK()) { 100 throw new RuntimeException(JdbcI18n.invalidServerResponse.text(url, response.asString())); 101 } 102 return new Workspaces(response.json()); 103 } 104 105 /** 106 * Returns all the node types that are available in the repository from {@code repoUrl} 107 * 108 * @return a {@link NodeTypes} instance; never {@code null} 109 */ 110 public NodeTypes getNodeTypes() { 111 String url = jsonRestClient.appendToURL(ITEMS_METHOD, NODE_TYPES_SEGMENT); 112 JSONRestClient.Response response = jsonRestClient.doGet(url); 113 if (!response.isOK()) { 114 throw new RuntimeException(JdbcI18n.invalidServerResponse.text(url, response.asString())); 115 } 116 return new NodeTypes(response.json()); 117 } 118 119 /** 120 * Runs a query in the specified language against the repository from {@code repoUrl}. 121 * 122 * @param query a {@code String}, never {@code null} 123 * @param queryLanguage the language of the query, never {@code null} 124 * @return a {@link QueryResult} instance, never {@code null} 125 * @see javax.jcr.query.Query 126 */ 127 public QueryResult query( String query, 128 String queryLanguage ) { 129 String url = jsonRestClient.appendToURL(QUERY_METHOD); 130 String contentType = contentTypeForQueryLanguage(queryLanguage); 131 JSONRestClient.Response response = jsonRestClient.postStream(new ByteArrayInputStream(query.getBytes()), url, contentType); 132 if (!response.isOK()) { 133 throw new RuntimeException(JdbcI18n.invalidServerResponse.text(url, response.asString())); 134 } 135 return new QueryResult(response.json()); 136 } 137 138 /** 139 * Returns a string representation of a query plan in a given language. 140 * 141 * @param query a {@code String}, never {@code null} 142 * @param queryLanguage the language of the query, never {@code null} 143 * @return a {@code String} description of the plan, never {@code null} 144 */ 145 public String queryPlan( String query, 146 String queryLanguage ) { 147 String url = jsonRestClient.appendToURL(QUERY_PLAN_METHOD); 148 String contentType = contentTypeForQueryLanguage(queryLanguage); 149 JSONRestClient.Response response = jsonRestClient.postStreamTextPlain(new ByteArrayInputStream(query.getBytes()), url, 150 contentType); 151 if (!response.isOK()) { 152 throw new RuntimeException(JdbcI18n.invalidServerResponse.text(url, response.asString())); 153 } 154 return response.asString(); 155 } 156 157 @SuppressWarnings( "deprecation" ) 158 private String contentTypeForQueryLanguage( String queryLanguage ) { 159 switch (queryLanguage) { 160 case Query.XPATH: { 161 return "application/jcr+xpath"; 162 } 163 case Query.SQL: { 164 return "application/jcr+sql"; 165 } 166 case Query.JCR_SQL2: { 167 return "application/jcr+sql2"; 168 } 169 case Query.JCR_JQOM: { 170 return "application/jcr+search"; 171 } 172 default: { 173 throw new IllegalArgumentException("Invalid query language: " + queryLanguage); 174 } 175 } 176 } 177}