/**
* Helios, OpenSource Monitoring
* Brought to you by the Helios Development Group
*
* Copyright 2007, Helios Development Group and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*
*/
package org.helios.apmrouter.dataservice.json.catalog;
import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.helios.apmrouter.catalog.MetricCatalogService;
import org.helios.apmrouter.catalog.api.impl.DataServiceInterceptor;
import org.helios.apmrouter.catalog.domain.AgentMetricSet;
import org.helios.apmrouter.catalog.domain.DomainObject;
import org.helios.apmrouter.catalog.domain.Metric;
import org.helios.apmrouter.dataservice.json.JSONRequestHandler;
import org.helios.apmrouter.dataservice.json.JsonRequest;
import org.helios.apmrouter.dataservice.json.JsonResponse;
import org.helios.apmrouter.dataservice.json.marshalling.JSONMarshaller;
import org.helios.apmrouter.server.ServerComponentBean;
import org.helios.apmrouter.util.URLHelper;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.engine.NamedQueryDefinition;
import org.hibernate.impl.SessionFactoryImpl;
import org.jboss.netty.channel.Channel;
import org.springframework.beans.factory.annotation.Autowired;
/**
* <p>Title: CatalogJSONDataService</p>
* <p>Description: Data services for the metric catalog service</p>
* <p>Company: Helios Development Group LLC</p>
* @author Whitehead (nwhitehead AT heliosdev DOT org)
* <p><code>org.helios.apmrouter.dataservice.json.catalog.CatalogJSONDataService</code></p>
*/
@JSONRequestHandler(name="catalog")
public class CatalogJSONDataService extends ServerComponentBean {
/** The metric catalog service */
protected MetricCatalogService catalog = null;
/** The MetridcURI subscription service */
protected MetricURISubscriptionService metricUriSubService = null;
/** The hibernate session factory */
protected SessionFactory sessionFactory = null;
/** The Json marshaller */
protected JSONMarshaller marshaller = null;
/** The named queries map */
protected final Map<String, NamedQueryDefinition> namedQueries = new HashMap<String, NamedQueryDefinition>();
/** The namedQueries map field */
private static final Field namedQueriesField;
/** The namedSqlQueries map field */
private static final Field namedSqlQueriesField;
static {
try {
namedQueriesField = SessionFactoryImpl.class.getDeclaredField("namedQueries");
namedQueriesField.setAccessible(true);
namedSqlQueriesField = SessionFactoryImpl.class.getDeclaredField("namedSqlQueries");
namedSqlQueriesField.setAccessible(true);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
/**
* {@inheritDoc}
* @see org.helios.apmrouter.server.ServerComponentBean#doStart()
*/
@SuppressWarnings("unchecked")
@Override
protected void doStart() throws Exception {
super.doStart();
namedQueries.putAll((Map<String, NamedQueryDefinition>) namedQueriesField.get(sessionFactory));
namedQueries.putAll((Map<String, NamedQueryDefinition>) namedSqlQueriesField.get(sessionFactory));
}
/**
* Sets the metric catalog service
* @param catalog the metric catalog service
*/
@Autowired(required=true)
public void setCatalog(MetricCatalogService catalog) {
this.catalog = catalog;
}
/**
* Sets the hibernate session factory
* @param sessionFactory the hibernate session factory
*/
@Autowired(required=true)
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
/**
* Returns a JSON list of hosts
* @param request The JSON request
* @param channel The channel to respond on
*/
@JSONRequestHandler(name="listhosts")
public void listHosts(JsonRequest request, Channel channel) {
boolean onlineOnly = request.getArgument(0, false);
Map<Integer, String> hosts = catalog.listHosts(onlineOnly);
JsonResponse response = request.response();
response.setContent(hosts);
channel.write(response);
}
/**
* Dumps a JSON stream describing all the named queries available to a JSON client
* @param request The json request
* @param channel The chennel to respond on
*/
@JSONRequestHandler(name="namedqueries")
public void listNamedQueries(JsonRequest request, Channel channel) {
JsonResponse response = request.response();
Map<String, NamedQueryDefinitionContainer> nqs = new HashMap<String, NamedQueryDefinitionContainer>();
for(Map.Entry<String, NamedQueryDefinition> entry: namedQueries.entrySet()) {
nqs.put(entry.getKey(), new NamedQueryDefinitionContainer(entry.getKey(), entry.getValue()));
}
response.setContent(nqs);
channel.write(response);
}
/**
* Processes a named query
* @param request The JSON encoded named query request
* @param channel The channel to write the response to
*/
@JSONRequestHandler(name="nq")
public void processNamedQuery(JsonRequest request, Channel channel) {
String name = request.getArgumentOrNull("name", String.class);
if(name==null) throw new RuntimeException("The named-query name was null", new Throwable());
Map<String, ?> params = request.getArgument("p", new HashMap<String, Object>());
Session session = null;
try {
session = sessionFactory.openSession(new DataServiceInterceptor());
Query query = session.getNamedQuery(name);
NamedQueryDefinition nqd = namedQueries.get(name);
for(Map.Entry<String, ?> param: params.entrySet()) {
String type = nqd.getParameterTypes().get(param.getKey()).toString();
PropertyEditor pe = PropertyEditorManager.findEditor(Class.forName(type));
if(param.getValue().toString().equals("null")) {
warn("Param with null value [", param.getKey(), "]");
}
pe.setAsText(param.getValue().toString());
query.setParameter(param.getKey(), pe.getValue());
}
List<?> results = query.list();
if(!results.isEmpty() && results.iterator().next() instanceof DomainObject) {
Object obj = results.toArray(new DomainObject[0]);
channel.write(request.response().setContent(obj));
} else {
channel.write(request.response().setContent(results));
}
} catch (Exception ex) {
error("Failed to execute named query [", name, "] with params [" + params + "]", ex);
} finally {
if(session!=null && session.isOpen()) try { session.close(); } catch (Exception e) {}
}
}
/**
* Returns an {@link AgentMetricSet} for the agent with the passed agent Id
* @param request The JSON encoded named query request
* @param channel The channel to write the response to
*/
@JSONRequestHandler(name="ams")
public void agentMetricSet(JsonRequest request, Channel channel) {
Session session = null;
try {
int agentId = Integer.parseInt(request.getArgument("agentId"));
session = sessionFactory.openSession();
request.response().setContent(AgentMetricSet.newInstance(session, agentId)).send(channel);
} catch (Exception ex) {
request.error("Failed to execute agentMetricSet [" + request + "]", ex);
error("Failed to execute agentMetricSet [" , request , "]", ex);
} finally {
if(session!=null && session.isOpen()) try { session.close(); } catch (Exception e) {/* No Op */}
}
}
/**
* Sets the object Json marshaller
* @param marshaller the object Json marshaller
*/
@Autowired(required=true)
public void setMarshaller(JSONMarshaller marshaller) {
this.marshaller = marshaller;
}
/**
* Processes the resolution of a client supplied {@link MetricURI} into a list of matching metrics
* @param request The JSON request
* @param channel The channel to write the response to
*/
@JSONRequestHandler(name="metricuri")
public void resolveMetricURI(JsonRequest request, Channel channel) {
String muri = request.getArgument("uri");
Boolean subscribe = request.getArgument("sub", Boolean.FALSE);
try {
metricUriSubService.resolveMetricURI(MetricURI.getMetricURI(muri), request.response(), channel, subscribe);
} catch (Exception ex) {
error("Failed to resolve MetricURI [" , request , "]", ex);
throw new RuntimeException("Failed to resolve MetricURI [" + request + "]", ex);
}
}
/**
* Subscribes the passed channel to the resolved {@link MetricURI}
* @param request The JSON request
* @param channel The channel to subscribe
*/
@JSONRequestHandler(name="submetricuri")
public void subscribeMetricURI(JsonRequest request, Channel channel) {
String muri = request.getArgument("uri");
try {
MetricURI metricUri = MetricURI.getMetricURI(muri);
metricUriSubService.subscribeMetricURI(metricUri, request.response(), channel);
request.subConfirm(muri).setContent(metricUri.toJSON(false)).send(channel);
} catch (Exception ex) {
error("Failed to subscribe to MetricURI [" , request , "]", ex);
throw new RuntimeException("Failed to subscribe to MetricURI [" + request + "]", ex);
}
}
/**
* Writes the metric definitions that are the current members of the passed metric uri back to the calling client
* @param request The request [hopefully] containing a metric uri
* @param channel the channel to write the response to
*/
@JSONRequestHandler(name="resolvemetricuri")
public void resolveURI(JsonRequest request, Channel channel) {
String muri = request.getArgument("uri");
List<Metric> resp = metricUriSubService.getMetricsForURI(MetricURI.getMetricURI(URLHelper.toURI(muri)));
request.response().setContent(resp).send(channel);
}
/**
* Unsubscribes the passed channel to the resolved {@link MetricURI}
* @param request The JSON request
* @param channel The channel to unsubscribe
*/
@JSONRequestHandler(name="unsubmetricuri")
public void cancelMetricURISubscription(JsonRequest request, Channel channel) {
String muri = request.getArgument("uri");
try {
metricUriSubService.cancelMetricURISubscription(MetricURI.getMetricURI(muri), channel);
request.subCancel(muri).send(channel);
} catch (Exception ex) {
error("Failed to unsubscribe from MetricURI [" , request , "]", ex);
throw new RuntimeException("Failed to unsubscribe from MetricURI [" + request + "]", ex);
}
}
/**
* Returns the metric URI subscription service
* @return the metric URI subscription service
*/
public MetricURISubscriptionService getMetricUriSubService() {
return metricUriSubService;
}
/**
* Sets the metric URI subscription service
* @param metricUriSubService the metric URI subscription service to set
*/
@Autowired(required=true)
public void setMetricUriSubService(MetricURISubscriptionService metricUriSubService) {
this.metricUriSubService = metricUriSubService;
}
}