001 package org.hackystat.telemetry.service.server; 002 003 import java.util.Map; 004 005 import org.hackystat.dailyprojectdata.client.DailyProjectDataClient; 006 import org.hackystat.sensorbase.client.SensorBaseClient; 007 import org.hackystat.telemetry.analyzer.configuration.TelemetryDefinitionManagerFactory; 008 import org.hackystat.telemetry.service.prefetch.PrefetchManager; 009 import org.hackystat.telemetry.service.resource.cache.CacheResource; 010 import org.hackystat.telemetry.service.resource.chart.ChartDataResource; 011 import org.hackystat.telemetry.service.resource.chart.ChartDefinitionResource; 012 import org.hackystat.telemetry.service.resource.chart.ChartsResource; 013 import org.hackystat.telemetry.service.resource.ping.PingResource; 014 import org.hackystat.utilities.logger.HackystatLogger; 015 import org.hackystat.utilities.logger.RestletLoggerUtil; 016 import org.restlet.Application; 017 import org.restlet.Component; 018 import org.restlet.Guard; 019 import org.restlet.Restlet; 020 import org.restlet.Router; 021 import org.restlet.data.Protocol; 022 023 import static org.hackystat.telemetry.service.server.ServerProperties.CONTEXT_ROOT_KEY; 024 import static org.hackystat.telemetry.service.server.ServerProperties.DAILYPROJECTDATA_FULLHOST_KEY; 025 import static org.hackystat.telemetry.service.server.ServerProperties.HOSTNAME_KEY; 026 import static org.hackystat.telemetry.service.server.ServerProperties.LOGGING_LEVEL_KEY; 027 import static org.hackystat.telemetry.service.server.ServerProperties.PORT_KEY; 028 import static org.hackystat.telemetry.service.server.ServerProperties.SENSORBASE_FULLHOST_KEY; 029 030 import java.util.logging.Logger; 031 032 import javax.xml.bind.JAXBContext; 033 034 /** 035 * Sets up the HTTP Server process and dispatching to the associated resources. 036 * @author Philip Johnson 037 */ 038 public class Server extends Application { 039 040 /** Holds the Restlet Component associated with this Server. */ 041 private Component component; 042 043 /** Holds the host name associated with this Server. */ 044 private String hostName; 045 046 /** Holds the HackystatLogger for this Service. */ 047 private Logger logger; 048 049 /** Holds the ServerProperties instance for this Service. */ 050 private ServerProperties properties; 051 052 /** 053 * Creates a new instance of a Telemetry HTTP server using the telemetry.properties configuration. 054 * @return The Server instance created. 055 * @throws Exception If problems occur starting up this server. 056 */ 057 public static Server newInstance() throws Exception { 058 return newInstance(new ServerProperties()); 059 } 060 061 /** 062 * Creates a new instance of a Telemetry HTTP server suitable for unit testing. 063 * Telemetry properties are initialized from the User's telemetry.properties file, 064 * then set to their "testing" versions. 065 * @return The Server instance created. 066 * @throws Exception If problems occur starting up this server. 067 */ 068 public static Server newTestInstance() throws Exception { 069 ServerProperties properties = new ServerProperties(); 070 properties.setTestProperties(); 071 return newInstance(properties); 072 } 073 074 /** 075 * Creates a new instance of a Telemetry HTTP server, listening on the supplied port. 076 * @param properties The ServerProperties instance. 077 * @return The Server instance created. 078 * @throws Exception If problems occur starting up this server. 079 */ 080 public static Server newInstance(ServerProperties properties) throws Exception { 081 Server server = new Server(); 082 server.logger = HackystatLogger.getLogger("org.hackystat.telemetry.server", "telemetry"); 083 server.properties = properties; 084 server.hostName = "http://" + 085 server.properties.get(HOSTNAME_KEY) + 086 ":" + 087 server.properties.get(PORT_KEY) + 088 "/" + 089 server.properties.get(CONTEXT_ROOT_KEY) + 090 "/"; 091 int port = Integer.valueOf(server.properties.get(PORT_KEY)); 092 server.component = new Component(); 093 server.component.getServers().add(Protocol.HTTP, port); 094 server.component.getDefaultHost() 095 .attach("/" + server.properties.get(CONTEXT_ROOT_KEY), server); 096 097 098 // Create and store the JAXBContext instances on the server context. 099 // They are supposed to be thread safe. 100 Map<String, Object> attributes = server.getContext().getAttributes(); 101 JAXBContext chartJAXB = JAXBContext.newInstance( 102 org.hackystat.telemetry.service.resource.chart.jaxb.ObjectFactory.class); 103 attributes.put("ChartJAXB", chartJAXB); 104 105 // Provide a pointer to this server in the Context so that Resources can get at this server. 106 attributes.put("TelemetryServer", server); 107 108 // Disable restlet logging unless dont.disable.restlet.logging is "true". 109 RestletLoggerUtil.disableLogging(); 110 111 // Now let's open for business. 112 server.logger.warning("Host: " + server.hostName); 113 HackystatLogger.setLoggingLevel(server.logger, server.properties.get(LOGGING_LEVEL_KEY)); 114 server.logger.info(server.properties.echoProperties()); 115 String sensorBaseHost = server.properties.get(SENSORBASE_FULLHOST_KEY); 116 117 // Read in all telemetry definitions and create the singleton. 118 String defDir = server.properties.get(ServerProperties.DEF_DIR_KEY); 119 TelemetryDefinitionManagerFactory.buildGlobalPersistentInstance(defDir); 120 121 String dailyProjectDataHost = server.properties.get(DAILYPROJECTDATA_FULLHOST_KEY); 122 boolean sensorBaseOK = SensorBaseClient.isHost(sensorBaseHost); 123 boolean dailyProjectDataOK = DailyProjectDataClient.isHost(dailyProjectDataHost); 124 server.logger.warning("Service SensorBase " + sensorBaseHost + 125 ((sensorBaseOK) ? " was contacted successfully." : 126 " NOT AVAILABLE. Therefore, the Telemetry service will not run correctly.")); 127 server.logger.warning("Service DailyProjectData " + dailyProjectDataHost + 128 ((dailyProjectDataOK) ? " was contacted successfully." : 129 " NOT AVAILABLE. Therefore, the Telemetry service will not run correctly.")); 130 server.logger.warning("Telemetry (Version " + getVersion() + ") now running."); 131 server.component.start(); 132 // Now start up the Prefetch service. 133 new PrefetchManager(server); 134 return server; 135 } 136 137 /** 138 * Starts up the web service. Control-c to exit. 139 * @param args Ignored. 140 * @throws Exception if problems occur. 141 */ 142 public static void main(final String[] args) throws Exception { 143 Server.newInstance(); 144 } 145 146 /** 147 * Dispatch to the specific Telemetry resource based upon the URI. 148 * We will authenticate all requests. 149 * @return The router Restlet. 150 */ 151 @Override 152 public Restlet createRoot() { 153 // First, create a Router that will have a Guard placed in front of it so that this Router's 154 // requests will require authentication. 155 Router authRouter = new Router(getContext()); 156 authRouter.attach("/charts", ChartsResource.class); 157 authRouter.attach("/chart/{chart}", ChartDefinitionResource.class); 158 authRouter.attach("/chart/{chart}/{email}/{project}/{granularity}/{start}/{end}", 159 ChartDataResource.class); 160 authRouter.attach("/chart/{chart}/{email}/{project}/{granularity}/{start}/{end}?params={params}" 161 , ChartDataResource.class); 162 authRouter.attach("/cache/", CacheResource.class); 163 authRouter.attach("/cache/{email}/{project}", CacheResource.class); 164 // Here's the Guard that we will place in front of authRouter. 165 Guard guard = new Authenticator(getContext(), 166 this.getServerProperties().get(SENSORBASE_FULLHOST_KEY), 167 this.getServerProperties().get(DAILYPROJECTDATA_FULLHOST_KEY)); 168 guard.setNext(authRouter); 169 170 // Now create our "top-level" router which will allow the Ping URI to proceed without 171 // authentication, but all other URI patterns will go to the guarded Router. 172 Router router = new Router(getContext()); 173 router.attach("/ping", PingResource.class); 174 router.attach("/ping?user={user}&password={password}", PingResource.class); 175 router.attachDefault(guard); 176 return router; 177 } 178 179 180 /** 181 * Returns the version associated with this Package, if available from the jar file manifest. 182 * If not being run from a jar file, then returns "Development". 183 * @return The version. 184 */ 185 public static String getVersion() { 186 String version = 187 Package.getPackage("org.hackystat.telemetry.service.server").getImplementationVersion(); 188 return (version == null) ? "Development" : version; 189 } 190 191 /** 192 * Returns the host name associated with this server. 193 * Example: "http://localhost:9878/telemetry" 194 * @return The host name. 195 */ 196 public String getHostName() { 197 return this.hostName; 198 } 199 200 /** 201 * Returns the ServerProperties instance associated with this server. 202 * @return The server properties. 203 */ 204 public ServerProperties getServerProperties() { 205 return this.properties; 206 } 207 208 /** 209 * Returns the logger for this service. 210 * @return The logger. 211 */ 212 @Override 213 public Logger getLogger() { 214 return this.logger; 215 } 216 } 217