001/* 002 * (C) Copyright 2011 Nuxeo SAS (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * Julien Carsique 016 * 017 */ 018 019package org.nuxeo.launcher.monitoring; 020 021import java.io.BufferedReader; 022import java.io.BufferedWriter; 023import java.io.IOException; 024import java.io.InputStreamReader; 025import java.io.OutputStreamWriter; 026import java.net.HttpURLConnection; 027import java.net.MalformedURLException; 028import java.net.SocketTimeoutException; 029import java.net.URL; 030 031import org.apache.commons.io.IOUtils; 032import org.apache.commons.logging.Log; 033import org.apache.commons.logging.LogFactory; 034import org.nuxeo.launcher.config.ConfigurationGenerator; 035 036/** 037 * HTTP client monitoring Nuxeo server starting status 038 * 039 * @see org.nuxeo.ecm.core.management.statuses.StatusServlet 040 * @since 5.5 041 */ 042public class StatusServletClient { 043 044 private static final Log log = LogFactory.getLog(StatusServletClient.class); 045 046 protected static final String URL_PATTERN = "runningstatus"; 047 048 protected static final String POST_PARAM = "info"; 049 050 protected static final String POST_PARAM_STARTED = "started"; 051 052 protected static final String POST_PARAM_SUMMARY = "summary"; 053 054 private static final int TIMEOUT = 1000; 055 056 private static final int SUMMARY_TIMEOUT = 2000; 057 058 private URL url; 059 060 private HttpURLConnection server; 061 062 private int timeout; 063 064 private boolean startupFine = false; 065 066 private String key; 067 068 /** 069 * Set secure key used for connection 070 * 071 * @param key any {@link String} 072 */ 073 public void setKey(String key) { 074 this.key = key; 075 } 076 077 /** 078 * @param configurationGenerator 079 */ 080 public StatusServletClient(ConfigurationGenerator configurationGenerator) { 081 final String servletURL = configurationGenerator.getUserConfig().getProperty( 082 ConfigurationGenerator.PARAM_LOOPBACK_URL) 083 + "/" + URL_PATTERN; 084 try { 085 url = new URL(servletURL); 086 } catch (MalformedURLException e) { 087 log.error("Malformed URL: " + servletURL, e); 088 } 089 } 090 091 /** 092 * @return true if Nuxeo finished starting 093 * @throws SocketTimeoutException 094 */ 095 public boolean isStarted() throws SocketTimeoutException { 096 timeout = TIMEOUT; 097 return post(POST_PARAM, POST_PARAM_STARTED); 098 } 099 100 /** 101 * @param postParam 102 * @param postParamStarted 103 * @return 104 * @throws SocketTimeoutException 105 */ 106 private boolean post(String postParam, String postParamStarted) throws SocketTimeoutException { 107 return post(postParam, postParamStarted, null); 108 } 109 110 /** 111 * @return true if succeed to connect on StatusServlet 112 * @throws SocketTimeoutException 113 */ 114 public boolean init() throws SocketTimeoutException { 115 try { 116 timeout = TIMEOUT; 117 connect("GET"); 118 } catch (SocketTimeoutException e) { 119 throw e; 120 } catch (IOException e) { 121 return false; 122 } finally { 123 disconnect(); 124 } 125 return true; 126 } 127 128 protected synchronized void disconnect() { 129 if (server != null) { 130 server.disconnect(); 131 server = null; 132 } 133 notifyAll(); 134 } 135 136 protected synchronized void connect(String method) throws IOException { 137 while (server != null) { 138 try { 139 wait(); 140 } catch (InterruptedException e) { 141 // do nothing 142 } 143 } 144 server = (HttpURLConnection) url.openConnection(); 145 server.setConnectTimeout(timeout); 146 server.setReadTimeout(timeout); 147 server.setDoInput(true); 148 server.setDoOutput(true); 149 server.setRequestMethod(method); 150 server.setRequestProperty("Content-type", "application/x-www-form-urlencoded"); 151 server.connect(); 152 } 153 154 /** 155 * @return Nuxeo server startup summary (components loading status) 156 * @throws SocketTimeoutException 157 */ 158 public String getStartupSummary() throws SocketTimeoutException { 159 timeout = SUMMARY_TIMEOUT; 160 StringBuilder sb = new StringBuilder(); 161 startupFine = post(POST_PARAM, POST_PARAM_SUMMARY, sb); 162 return sb.toString(); 163 } 164 165 protected boolean post(String param, String value, StringBuilder response) throws SocketTimeoutException { 166 String post = param + "=" + value; 167 post += "&key=" + key; 168 try { 169 connect("POST"); 170 BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(server.getOutputStream())); 171 bw.write(post, 0, post.length()); 172 bw.close(); 173 return getResponse(response); 174 } catch (SocketTimeoutException e) { 175 throw e; 176 } catch (IOException e) { 177 return false; 178 } finally { 179 disconnect(); 180 } 181 } 182 183 protected boolean getResponse(StringBuilder response) throws IOException { 184 String line; 185 boolean answer; 186 BufferedReader s = null; 187 try { 188 s = new BufferedReader(new InputStreamReader(server.getInputStream())); 189 // First line is a status (true or false) 190 answer = Boolean.parseBoolean(s.readLine()); 191 // Next (if exists) is a response body 192 while ((line = s.readLine()) != null) { 193 if (response != null) { 194 response.append(line + "\n"); 195 } 196 } 197 } catch (IOException e) { 198 throw e; 199 } finally { 200 IOUtils.closeQuietly(s); 201 } 202 return answer; 203 } 204 205 /** 206 * Return detected status of Nuxeo server by last call to {@link #getStartupSummary()} 207 * 208 * @return true if everything is fine; false is there was any error or status is unknown 209 */ 210 public boolean isStartupFine() { 211 return startupFine; 212 } 213}