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