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