Fixes comment typo
[mkjsf-moved-to-github.git] / src / main / java / com / indexdata / mkjsf / pazpar2 / sp / ServiceProxyClient.java
1 package com.indexdata.mkjsf.pazpar2.sp;\r
2 \r
3 import static com.indexdata.mkjsf.utils.Utils.nl;\r
4 \r
5 import java.io.BufferedReader;\r
6 import java.io.File;\r
7 import java.io.FileReader;\r
8 import java.io.IOException;\r
9 import java.util.ArrayList;\r
10 import java.util.HashMap;\r
11 import java.util.List;\r
12 import java.util.Map;\r
13 import java.util.StringTokenizer;\r
14 \r
15 import org.apache.http.Header;\r
16 import org.apache.http.HttpEntity;\r
17 import org.apache.http.HttpResponse;\r
18 import org.apache.http.StatusLine;\r
19 import org.apache.http.client.ClientProtocolException;\r
20 import org.apache.http.client.HttpClient;\r
21 import org.apache.http.client.ResponseHandler;\r
22 import org.apache.http.client.methods.HttpGet;\r
23 import org.apache.http.client.methods.HttpPost;\r
24 import org.apache.http.conn.ClientConnectionManager;\r
25 import org.apache.http.conn.scheme.PlainSocketFactory;\r
26 import org.apache.http.conn.scheme.Scheme;\r
27 import org.apache.http.conn.scheme.SchemeRegistry;\r
28 import org.apache.http.entity.ByteArrayEntity;\r
29 import org.apache.http.entity.FileEntity;\r
30 import org.apache.http.impl.client.DefaultHttpClient;\r
31 import org.apache.http.impl.conn.PoolingClientConnectionManager;\r
32 import org.apache.http.util.EntityUtils;\r
33 import org.apache.log4j.Logger;\r
34 \r
35 import com.indexdata.mkjsf.config.Configuration;\r
36 import com.indexdata.mkjsf.config.ConfigurationReader;\r
37 import com.indexdata.mkjsf.errors.ConfigurationException;\r
38 import com.indexdata.mkjsf.pazpar2.CommandResponse;\r
39 import com.indexdata.mkjsf.pazpar2.SearchClient;\r
40 import com.indexdata.mkjsf.pazpar2.commands.CommandParameter;\r
41 import com.indexdata.mkjsf.pazpar2.commands.Pazpar2Command;\r
42 import com.indexdata.mkjsf.pazpar2.commands.sp.AuthCommand;\r
43 import com.indexdata.mkjsf.pazpar2.data.CommandError;\r
44 import com.indexdata.mkjsf.pazpar2.sp.auth.ServiceProxyUser;\r
45 import com.indexdata.mkjsf.utils.Utils;\r
46 \r
47 public class ServiceProxyClient implements SearchClient {\r
48     \r
49   private static final long serialVersionUID = -4031644009579840277L;\r
50   private static Logger logger = Logger.getLogger(ServiceProxyClient.class);\r
51   public static final String MODULENAME = "proxyclient";\r
52   public static final String SERVICE_PROXY_URL = "SERVICE_PROXY_URL";\r
53   public static final String SP_INIT_DOC_PATHS = "SP_INIT_DOC_PATHS";\r
54   private String selectedServiceUrl = "";\r
55   private List<String> serviceUrls = new ArrayList<String>();\r
56   private List<String> initDocPaths = null;\r
57   private Configuration config = null;\r
58   \r
59   ProxyPz2ResponseHandler handler = new ProxyPz2ResponseHandler();\r
60   private transient HttpClient client;  \r
61   private Pazpar2Command checkAuth = null;\r
62   private Pazpar2Command ipAuth = null;\r
63 \r
64   public ServiceProxyClient () {\r
65     SchemeRegistry schemeRegistry = new SchemeRegistry();\r
66     schemeRegistry.register(new Scheme("http", 80, PlainSocketFactory.getSocketFactory()));\r
67     ClientConnectionManager cm = new PoolingClientConnectionManager(schemeRegistry);\r
68     client = new DefaultHttpClient(cm);\r
69   }\r
70     \r
71   @Override\r
72   public void configure (ConfigurationReader configReader) {\r
73     logger.info(Utils.objectId(this) + " is configuring using the provided " + Utils.objectId(configReader));\r
74     try {\r
75       config = configReader.getConfiguration(this);      \r
76       serviceUrls = getMultiProperty(config.get(SERVICE_PROXY_URL),",");\r
77       if (serviceUrls.size()==1) {\r
78         selectedServiceUrl = serviceUrls.get(0);\r
79       }\r
80       this.initDocPaths = getMultiProperty(config.get(SP_INIT_DOC_PATHS),",");\r
81       checkAuth = new AuthCommand(null);\r
82       checkAuth.setParameterInState(new CommandParameter("action","=","check"));\r
83       ipAuth = new AuthCommand(null);\r
84       ipAuth.setParameterInState(new CommandParameter("action","=","ipauth"));\r
85     } catch (ConfigurationException c) {\r
86       // TODO: \r
87       c.printStackTrace();\r
88     }    \r
89   }\r
90   \r
91   private List<String> getMultiProperty(String prop, String separator) {\r
92     List<String> props = new ArrayList<String>();\r
93     if (prop != null) {      \r
94       StringTokenizer tokenizer = new StringTokenizer(prop,separator);\r
95       while (tokenizer.hasMoreElements()) {\r
96         props.add(tokenizer.nextToken());\r
97       }     \r
98     }\r
99     return props;\r
100   }\r
101   \r
102   public boolean authenticate (ServiceProxyUser user) {\r
103     logger.info("Authenticating [" + user.getProperty("name") + "]");            \r
104     Pazpar2Command auth = new AuthCommand(null);\r
105     auth.setParametersInState(new CommandParameter("action","=","login"), \r
106                               new CommandParameter("username","=",user.getProperty("name")), \r
107                               new CommandParameter("password","=",user.getProperty("password")));                                \r
108     ServiceProxyCommandResponse commandResponse = send(auth);\r
109     String responseStr = commandResponse.getResponseString();\r
110     logger.info(responseStr);      \r
111     if (responseStr.contains("FAIL")) {\r
112       user.credentialsAuthenticationSucceeded(false);\r
113       return false;\r
114     } else {\r
115       user.credentialsAuthenticationSucceeded(true);\r
116       return true;\r
117     }      \r
118   }\r
119   \r
120   public boolean checkAuthentication (ServiceProxyUser user) {    \r
121     ServiceProxyCommandResponse commandResponse = send(checkAuth);      \r
122     String responseStr = commandResponse.getResponseString();    \r
123     logger.info(responseStr);\r
124     if (responseStr.contains("FAIL")) {  \r
125       user.authenticationCheckFailed();\r
126       return false;\r
127     } else {                \r
128       return true;\r
129     }      \r
130   }\r
131   \r
132   public boolean ipAuthenticate (ServiceProxyUser user) {\r
133     ServiceProxyCommandResponse commandResponse = send(ipAuth);      \r
134     String responseStr = commandResponse.getResponseString();\r
135     logger.info(responseStr);\r
136     if (responseStr.contains("FAIL")) {\r
137       user.ipAuthenticationSucceeded(false);        \r
138       return false;\r
139     } else {\r
140       user.ipAuthenticationSucceeded(true);\r
141       return true;\r
142     }          \r
143   }\r
144   \r
145   public boolean isAuthenticatingClient () {\r
146     return true;\r
147   }\r
148   \r
149   public boolean isAuthenticated (ServiceProxyUser user) {\r
150     if (user.getProperty("name") != null && user.getProperty("password") != null) {\r
151       return checkAuthentication(user);\r
152     } else {\r
153       return false;\r
154     }\r
155   }\r
156   \r
157   /**\r
158    * Makes the request\r
159    * @param request\r
160    * @return HTTP response as a String\r
161    * @throws ClientProtocolException\r
162    * @throws IOException\r
163    */\r
164   private ServiceProxyCommandResponse send(Pazpar2Command command) {\r
165     ServiceProxyCommandResponse commandResponse = null;\r
166     String url = selectedServiceUrl + "?" + command.getEncodedQueryString(); \r
167     logger.info("Sending request "+url);    \r
168     HttpGet httpget = new HttpGet(url);     \r
169     byte[] response = null;\r
170     try {\r
171       response = client.execute(httpget, handler);\r
172       if (handler.getStatusCode()==200) {\r
173         commandResponse = new ServiceProxyCommandResponse(handler.getStatusCode(),response,handler.getContentType());\r
174       } else {\r
175         logger.error("Service Proxy status code: " + handler.getStatusCode());\r
176         commandResponse = new ServiceProxyCommandResponse(handler.getStatusCode(),CommandError.insertPazpar2ErrorXml(command.getCommandName(), "Service Proxy error occurred", new String(response,"UTF-8")),"text/xml");                       \r
177       }       \r
178     } catch (Exception e) {\r
179       e.printStackTrace();\r
180       commandResponse = new ServiceProxyCommandResponse(-1,CommandError.createErrorXml(command.getCommandName(), e.getClass().getSimpleName(), (e.getMessage()!= null ? e.getMessage() : "") + (e.getCause()!=null ? e.getCause().getMessage() : "")),"text/xml");\r
181     }\r
182     return commandResponse; \r
183   }\r
184   \r
185   public class ProxyPz2ResponseHandler implements ResponseHandler<byte[]> {\r
186     private StatusLine statusLine = null;\r
187     private Header contentType = null;\r
188     public byte[] handleResponse(HttpResponse response) throws ClientProtocolException, IOException {\r
189       byte[] resp = null;\r
190       HttpEntity entity = response.getEntity();      \r
191       statusLine = response.getStatusLine();\r
192       if (entity != null) {        \r
193         resp = EntityUtils.toByteArray(entity);        \r
194         contentType = response.getEntity().getContentType();        \r
195       }       \r
196       EntityUtils.consume(entity);      \r
197       return resp;\r
198     }\r
199     public int getStatusCode() {\r
200       return statusLine.getStatusCode();\r
201     }    \r
202     public String getReasonPhrase() {\r
203       return statusLine.getReasonPhrase();\r
204     }\r
205     public String getContentType () {\r
206       return (contentType != null ? contentType.getValue() : "Content-Type not known"); \r
207     }\r
208   }\r
209 \r
210   public int getStatusCode () {\r
211     return handler.getStatusCode();\r
212   }\r
213   \r
214   public String getReasonPhrase() {\r
215     return handler.getReasonPhrase();\r
216   }\r
217 \r
218   @Override\r
219   public void setSearchCommand(Pazpar2Command command) {\r
220     // Do nothing, Service Proxy is handling this    \r
221   }\r
222 \r
223   @Override\r
224   public CommandResponse executeCommand(Pazpar2Command command) {\r
225     return send(command);\r
226   }\r
227 \r
228   public ServiceProxyClient cloneMe() {\r
229     logger.debug("Cloning Pz2Client");\r
230     ServiceProxyClient clone = new ServiceProxyClient();\r
231     clone.client = this.client;\r
232     clone.serviceUrls = this.serviceUrls;\r
233     clone.selectedServiceUrl = this.selectedServiceUrl;\r
234     clone.initDocPaths = this.initDocPaths;\r
235     return clone;\r
236   }\r
237 \r
238   @Override\r
239   public Map<String, String> getDefaults() {    \r
240     return new HashMap<String,String>();\r
241   }\r
242 \r
243   @Override\r
244   public String getModuleName() {\r
245     return MODULENAME;\r
246   }\r
247   \r
248   @Override\r
249   public List<String> documentConfiguration () {\r
250     List<String> doc = new ArrayList<String>();\r
251     doc.add(nl+ MODULENAME + " was configured to access the Pazpar2 service proxy at: " + (selectedServiceUrl.length()>0 ? selectedServiceUrl : "[not defined yet]"));\r
252     return null;\r
253   }\r
254   \r
255   public ServiceProxyCommandResponse postInitDoc (String filePath) throws IOException {\r
256     logger.info("Looking to post the file in : [" + filePath +"]");\r
257     HttpPost post = new HttpPost(selectedServiceUrl+"?command=init&includeDebug=yes");\r
258     File initDoc = new File(filePath);\r
259     logger.info("Posting to SP: ");\r
260     if (logger.isDebugEnabled()) {\r
261       BufferedReader reader = new BufferedReader(new FileReader(initDoc));\r
262       String line;\r
263       while ( (line = reader.readLine()) != null) {\r
264         System.out.println(line);\r
265       }\r
266       reader.close();\r
267     }\r
268     post.setEntity(new FileEntity(initDoc));\r
269     byte[] response = client.execute(post, handler);\r
270     logger.debug("Response on POST was: " + new String(response,"UTF-8"));    \r
271     return new ServiceProxyCommandResponse(handler.getStatusCode(),response,handler.getContentType());    \r
272   }\r
273   \r
274   public List<String> getInitDocPaths () {\r
275     logger.debug("Get init doc paths ");\r
276     logger.debug("length: " + initDocPaths.size());\r
277     return initDocPaths;\r
278   }\r
279   \r
280   public ServiceProxyCommandResponse postInitDoc(byte[] initDoc, boolean includeDebug) throws IOException {\r
281     HttpPost post = new HttpPost(selectedServiceUrl+"?command=init" + (includeDebug? "&includeDebug=yes" : ""));\r
282     post.setEntity(new ByteArrayEntity(initDoc));\r
283     byte[] response = client.execute(post, handler);\r
284     logger.debug("Response on POST was: " + new String(response,"UTF-8"));    \r
285     return new ServiceProxyCommandResponse(handler.getStatusCode(),response,handler.getContentType());    \r
286   }\r
287   \r
288   public void setServiceProxyUrl (String url) {\r
289     selectedServiceUrl = url;\r
290   }\r
291   \r
292   public String getServiceProxyUrl () {\r
293     return selectedServiceUrl;\r
294   }\r
295   \r
296   public List<String> getServiceProxyUrls () {\r
297     return serviceUrls;\r
298   }\r
299     \r
300   public Configuration getConfiguration () {\r
301     return config;\r
302   }\r
303   \r
304 }\r