/*******************************************************************************
* Copyright (c) 2006-2010 eBay Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*******************************************************************************/
package org.ebayopensource.turmeric.runtime.common.impl.internal.service;
import java.nio.charset.Charset;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.ebayopensource.turmeric.runtime.common.binding.DataBindingDesc;
import org.ebayopensource.turmeric.runtime.common.pipeline.LoggingHandler;
import org.ebayopensource.turmeric.runtime.common.service.ComponentStatusDataProvider;
import org.ebayopensource.turmeric.runtime.common.service.ServiceId;
import org.ebayopensource.turmeric.runtime.common.service.ServiceOperationDesc;
import org.ebayopensource.turmeric.runtime.common.types.G11nOptions;
import com.ebay.kernel.component.IComponentStatusXml;
import com.ebay.kernel.markdown.MarkdownStateSnapshot;
import com.ebay.kernel.util.StringUtils;
import com.ebay.kernel.util.xml.IXmlStreamWriter;
import com.ebay.kernel.util.xml.XmlStreamUtil;
/**
* @author ichernyshev
*/
public abstract class BaseServiceBrowserCompStatus implements IComponentStatusXml {
private final String m_name;
private final String m_prefix;
private final boolean m_isClient;
public BaseServiceBrowserCompStatus(String name, boolean isClient, String prefix) {
m_name = name;
m_isClient = isClient;
m_prefix = prefix;
}
public final String getName() {
return m_name;
}
public final String getAlias() {
return null;
}
public final String getStatus() {
return "created";
}
public final List getProperties() {
return Collections.EMPTY_LIST;
}
public final void renderXml(IXmlStreamWriter xmlWriter, Map<String,String> props) {
xmlWriter.writeStartElement(m_prefix + "ServiceBrowser");
try {
BaseServiceDescFactory<ServiceDesc> factory;
if (m_isClient) {
@SuppressWarnings("unchecked")
BaseServiceDescFactory<ServiceDesc> factory2 = BaseServiceDescFactory.getClientInstance();
factory = factory2;
} else {
@SuppressWarnings("unchecked")
BaseServiceDescFactory<ServiceDesc> factory2 = BaseServiceDescFactory.getServerInstance();
factory = factory2;
}
String failedNamesViewStr = props.get("failed-only");
boolean isFailedNamesView = Boolean.parseBoolean(failedNamesViewStr);
if (isFailedNamesView) {
xmlWriter.writeAttribute("failed-names-view", "true");
renderFailedServices(factory, xmlWriter, props, true);
return;
}
Collection<ServiceDesc> descs = factory.getKnownServiceDescs();
String detailStr = props.get("detail");
if (detailStr != null) {
xmlWriter.writeAttribute("single-service", "true");
for (ServiceDesc desc: descs) {
String name = getDescName(desc.getServiceId());
if (!name.equals(detailStr)) {
continue;
}
renderServiceDesc(desc, true, xmlWriter, props);
}
return;
}
String fullViewStr = props.get("fullview");
boolean isFullView = Boolean.parseBoolean(fullViewStr);
Set<String> filter = null;
String filterStr = props.get("filter");
if (filterStr != null) {
List<String> names = StringUtils.splitStr(filterStr, ',', true);
if (!names.isEmpty()) {
filter = new HashSet<String>(names);
if (fullViewStr == null) {
isFullView = true;
}
}
}
for (ServiceDesc desc: descs) {
if (filter != null && !matchFilter(desc, filter)) {
continue;
}
renderServiceDesc(desc, isFullView, xmlWriter, props);
}
// TODO: add failed services HTML
renderFailedServices(factory, xmlWriter, props, false);
} finally {
xmlWriter.writeEndElement();
}
}
private String getDescName(ServiceId id) {
String adminName = id.getAdminName();
String subname = id.getServiceSubname();
StringBuilder sb = new StringBuilder();
sb.append(adminName);
if (subname != null) {
sb.append('.');
sb.append(subname);
}
return sb.toString();
}
private boolean matchFilter(ServiceDesc desc, Set<String> filter) {
if (filter.contains(desc.getAdminName())) {
return true;
}
String name = getDescName(desc.getServiceId());
return filter.contains(name);
}
private void renderFailedServices(BaseServiceDescFactory<ServiceDesc> factory,
IXmlStreamWriter xmlWriter, Map<String,String> props, boolean forceDisplay)
{
Map<ServiceId,Throwable> ids = factory.getFailedIds();
if (ids.isEmpty() && !forceDisplay) {
return;
}
xmlWriter.writeStartElement("FailedServices");
try {
for (Map.Entry<ServiceId,Throwable> e: ids.entrySet()) {
xmlWriter.writeStartElement("FailedService");
try {
ServiceId id = e.getKey();
Throwable error = e.getValue();
String name = getDescName(id);
xmlWriter.writeAttribute("name", name);
xmlWriter.writeAttribute("admin-name", id.getAdminName());
XmlStreamUtil.safeWriteChildCData(xmlWriter, "error", error.toString());
} finally {
xmlWriter.writeEndElement();
}
}
} finally {
xmlWriter.writeEndElement();
}
}
private void renderServiceDesc(ServiceDesc desc, boolean isFullView,
IXmlStreamWriter xmlWriter, Map<String,String> props)
{
xmlWriter.writeStartElement(m_prefix + "ServiceDesc");
try {
// write all relevant attributes
String name = getDescName(desc.getServiceId());
xmlWriter.writeAttribute("name", name);
xmlWriter.writeAttribute("admin-name", desc.getAdminName());
MarkdownStateSnapshot markdownState = getMarkdownStatus(desc, null);
boolean isDown = markdownState.isAlert();
xmlWriter.writeAttribute("is-down", String.valueOf(isDown));
boolean hasOpMarkdown = false;
Map<String,MarkdownStateSnapshot> opMarkdownStates = new HashMap<String,MarkdownStateSnapshot>();
for (ServiceOperationDesc op: desc.getAllOperations()) {
String opName = op.getName();
MarkdownStateSnapshot opMarkdownState = getMarkdownStatus(desc, opName);
opMarkdownStates.put(opName, opMarkdownState);
hasOpMarkdown |= opMarkdownState.isAlert();
}
if (!isDown && hasOpMarkdown) {
xmlWriter.writeAttribute("is-partial-down", String.valueOf(hasOpMarkdown));
}
renderServiceDescAttrs(desc, isFullView, xmlWriter, props);
// write all relevant elements
XmlStreamUtil.safeWriteChildCData(xmlWriter, "qname", desc.getCanonicalServiceName());
if (isDown) {
renderMarkdownElements(desc, markdownState, xmlWriter);
}
Class intfClass = desc.getServiceInterfaceClass();
if (intfClass != null) {
XmlStreamUtil.safeWriteChildCData(xmlWriter, "interface-class", intfClass.getName());
}
if (isFullView) {
XmlStreamUtil.safeWriteChildCData(xmlWriter, "request-pipeline-class",
desc.getRequestPipeline().getClass().getName());
XmlStreamUtil.safeWriteChildCData(xmlWriter, "response-pipeline-class",
desc.getResponsePipeline().getClass().getName());
XmlStreamUtil.safeWriteChildCData(xmlWriter, "request-dispatcher-class",
desc.getRequestDispatcher().getClass().getName());
XmlStreamUtil.safeWriteChildCData(xmlWriter, "response-dispatcher-class",
desc.getResponseDispatcher().getClass().getName());
}
if (isFullView) {
renderOperations(desc, opMarkdownStates, xmlWriter, props);
renderProtocolProcessors(desc, xmlWriter, props);
renderBindings(desc, xmlWriter, props);
renderLoggingHandlers(desc, xmlWriter, props);
}
renderServiceDescElements(desc, isFullView, xmlWriter, props);
} finally {
xmlWriter.writeEndElement();
}
}
private void renderMarkdownElements(ServiceDesc desc,
MarkdownStateSnapshot markdownState, IXmlStreamWriter xmlWriter)
{
XmlStreamUtil.safeWriteChildCData(xmlWriter, "markdown-status", markdownState.getStatus());
XmlStreamUtil.safeWriteChildCData(xmlWriter, "markdown-reason", markdownState.getReason());
}
private void renderOperations(ServiceDesc desc, Map<String,MarkdownStateSnapshot> opMarkdownStates,
IXmlStreamWriter xmlWriter, Map<String,String> props)
{
xmlWriter.writeStartElement("ServiceOperations");
try {
Collection<ServiceOperationDesc> ops = desc.getAllOperations();
ServiceOperationDesc[] ops2 = ops.toArray(new ServiceOperationDesc[ops.size()]);
// TODO: sort
for (int i=0; i<ops2.length; i++) {
ServiceOperationDesc op = ops2[i];
MarkdownStateSnapshot markdownState = opMarkdownStates.get(op.getName());
xmlWriter.writeStartElement("ServiceOperation");
try {
xmlWriter.writeAttribute("name", op.getName());
xmlWriter.writeAttribute("supported", String.valueOf(op.isSupported()));
if (markdownState != null) {
boolean isDown = markdownState.isAlert();
xmlWriter.writeAttribute("is-down", String.valueOf(isDown));
}
// TODO: add types
// TODO: add properties
} finally {
xmlWriter.writeEndElement();
}
}
} finally {
xmlWriter.writeEndElement();
}
}
private void renderProtocolProcessors(ServiceDesc desc, IXmlStreamWriter xmlWriter,
Map<String,String> props)
{
xmlWriter.writeStartElement("ServiceProtocolProcessors");
try {
Collection<ProtocolProcessorDesc> procs = desc.getAllProtocolProcessors();
ProtocolProcessorDesc[] procs2 = procs.toArray(new ProtocolProcessorDesc[procs.size()]);
// TODO: sort
for (int i=0; i<procs2.length; i++) {
ProtocolProcessorDesc proc = procs2[i];
xmlWriter.writeStartElement("ServiceProtocolProcessor");
try {
xmlWriter.writeAttribute("name", proc.getName());
XmlStreamUtil.safeWriteChildCData(xmlWriter, "class",
proc.getProcessor().getClass().getName());
// TODO: add supported payloads
renderCustomStatus(proc, xmlWriter, props);
} finally {
xmlWriter.writeEndElement();
}
}
} finally {
xmlWriter.writeEndElement();
}
}
private void renderBindings(ServiceDesc desc, IXmlStreamWriter xmlWriter,
Map<String,String> props)
{
xmlWriter.writeStartElement("ServiceDataBindings");
try {
Collection<DataBindingDesc> bindings = desc.getAllDataBindings();
DataBindingDesc[] bindings2 = bindings.toArray(new DataBindingDesc[bindings.size()]);
// TODO: sort
for (int i=0; i<bindings2.length; i++) {
DataBindingDesc binding = bindings2[i];
xmlWriter.writeStartElement("ServiceDataBinding");
try {
xmlWriter.writeAttribute("name", binding.getName());
XmlStreamUtil.safeWriteChildCData(xmlWriter, "payload",
binding.getPayloadType());
XmlStreamUtil.safeWriteChildCData(xmlWriter, "mime-type",
binding.getMimeType());
XmlStreamUtil.safeWriteChildCData(xmlWriter, "serializer",
binding.getSerializerFactory().getClass().getName());
XmlStreamUtil.safeWriteChildCData(xmlWriter, "deserializer",
binding.getDeserializerFactory().getClass().getName());
// TODO: add custom serializers
// TODO: add type converters
// TODO: add type list
} finally {
xmlWriter.writeEndElement();
}
}
} finally {
xmlWriter.writeEndElement();
}
}
private void renderLoggingHandlers(ServiceDesc desc, IXmlStreamWriter xmlWriter,
Map<String,String> props)
{
xmlWriter.writeStartElement("ServiceLoggingHandlers");
try {
Collection<LoggingHandler> handlers = desc.getLoggingHandlers();
LoggingHandler[] handlers2 = handlers.toArray(new LoggingHandler[handlers.size()]);
for (int i=0; i<handlers2.length; i++) {
LoggingHandler handler = handlers2[i];
xmlWriter.writeStartElement("ServiceLoggingHandler");
try {
XmlStreamUtil.safeWriteChildCData(xmlWriter, "class",
handler.getClass().getName());
renderCustomStatus(handler, xmlWriter, props);
} finally {
xmlWriter.writeEndElement();
}
}
} finally {
xmlWriter.writeEndElement();
}
}
protected final void writeG11Options(G11nOptions g11nOptions, IXmlStreamWriter xmlWriter, String name) {
Charset charset = g11nOptions.getCharset();
String globalId = g11nOptions.getGlobalId();
List<String> locales = g11nOptions.getLocales();
xmlWriter.writeStartElement(name);
try {
XmlStreamUtil.safeWriteChildCData(xmlWriter, "charset", charset.toString());
if (globalId != null) {
XmlStreamUtil.safeWriteChildCData(xmlWriter, "globalid", globalId);
}
if (locales != null) {
StringBuilder sb = new StringBuilder();
for (String locale: locales) {
if (sb.length() > 0) {
sb.append(',');
}
sb.append(locale);
}
if (sb.length() > 0) {
XmlStreamUtil.safeWriteChildCData(xmlWriter, "locales", sb.toString());
}
}
} finally {
xmlWriter.writeEndElement();
}
}
protected final void renderCustomStatus(Object obj, IXmlStreamWriter xmlWriter,
Map<String,String> props)
{
if (!(obj instanceof ComponentStatusDataProvider)) {
return;
}
ComponentStatusDataProvider provider = (ComponentStatusDataProvider)obj;
xmlWriter.writeStartElement("data");
try {
provider.writeStatusXml(xmlWriter, props);
} finally {
xmlWriter.writeEndElement();
}
}
protected abstract MarkdownStateSnapshot getMarkdownStatus(ServiceDesc desc, String operation);
protected abstract void renderServiceDescAttrs(ServiceDesc desc, boolean isFullView,
IXmlStreamWriter xmlWriter, Map<String,String> props);
protected abstract void renderServiceDescElements(ServiceDesc desc, boolean isFullView,
IXmlStreamWriter xmlWriter, Map<String,String> props);
}