/* * Copyright (c) 2005-2008, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. * * WSO2 Inc. licenses this file to you 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 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ package org.wso2.carbon.mediation.registry; import org.apache.synapse.registry.AbstractRegistry; import org.apache.synapse.registry.RegistryEntry; import org.apache.synapse.SynapseException; import org.apache.synapse.util.SynapseBinaryDataSource; import org.apache.axiom.om.OMNode; import org.apache.axiom.om.OMException; import org.apache.axiom.om.OMAbstractFactory; import org.apache.axiom.om.OMFactory; import org.apache.axiom.om.impl.builder.StAXOMBuilder; import org.apache.axiom.om.impl.llom.OMDocumentImpl; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.wso2.carbon.base.MultitenantConstants; import org.wso2.carbon.context.PrivilegedCarbonContext; import org.wso2.carbon.registry.core.*; import org.wso2.carbon.registry.core.service.RegistryService; import org.wso2.carbon.registry.core.utils.RegistryUtils; import org.wso2.carbon.registry.core.exceptions.RegistryException; import org.wso2.carbon.registry.core.Collection; import org.wso2.carbon.context.CarbonContext; import javax.xml.stream.*; import javax.activation.DataHandler; import java.util.Properties; import java.util.List; import java.util.ArrayList; import java.io.IOException; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; public class WSO2Registry extends AbstractRegistry { private static final Log log = LogFactory.getLog(WSO2Registry.class); public static final String CONFIG_REGISTRY_PREFIX = "conf:"; public static final String GOVERNANCE_REGISTRY_PREFIX = "gov:"; public static final String LOCAL_REGISTRY_PREFIX = "local:"; private static final String EXPIRY_TIME = "expiryTime"; private static final String CACHABLE_DURATION = "cachableDuration"; private static final String EXTENSIONS = "extensions"; private static final String ROOT = "root"; private static final int MAX_KEYS = 200; private Registry configRegistry; private Registry localRegistry; private Registry governanceRegistry; private String rootPath; private List<RegistryExtension> extensions = new ArrayList<RegistryExtension>(); private String domain; private int tenantId; public WSO2Registry() { RegistryService registryService = RegistryServiceHolder.getInstance().getRegistryService(); try { configRegistry = registryService.getConfigSystemRegistry( CarbonContext.getThreadLocalCarbonContext().getTenantId()); governanceRegistry = registryService.getGovernanceSystemRegistry( CarbonContext.getThreadLocalCarbonContext().getTenantId()); localRegistry = registryService.getLocalRepository( CarbonContext.getThreadLocalCarbonContext().getTenantId()); } catch (RegistryException e) { handleException("Error while initializing the mediation registry adapter", e); } } @Override public void init(Properties properties) { super.init(properties); //Saving tenant information as instance variables to use later when registry lookup calls comes via non-carbon //thread pools CarbonContext cc = CarbonContext.getThreadLocalCarbonContext(); domain = cc.getTenantDomain(); tenantId = cc.getTenantId(); String root = properties.getProperty(ROOT); if (root == null || "".equals(root)) { rootPath = RegistryConstants.ROOT_PATH; } else { if (!root.startsWith(RegistryConstants.PATH_SEPARATOR)) { root = RegistryConstants.PATH_SEPARATOR + root; } if (!root.endsWith(RegistryConstants.PATH_SEPARATOR)) { root += RegistryConstants.PATH_SEPARATOR; } rootPath = root; } String extensionsProperty = properties.getProperty(EXTENSIONS); if (extensionsProperty != null && !"".equals(extensionsProperty)) { if (log.isDebugEnabled()) { log.debug("Initializing mediation registry extensions"); } String[] classNames = extensionsProperty.split(","); for (String className : classNames) { registerExtension(className); } } } public OMNode lookup(String key) { setTenantInfo(); if (key == null) { handleException("Resource cannot be found."); } if ("".equals(key)) { handleException("Resource cannot be empty"); } if (log.isDebugEnabled()) { log.debug("==> Repository fetch of resource with key : " + key); } try { Resource resource = getResource(key); if (resource instanceof Collection) { return null; } if (resource == null) { // try via available extensions if (extensions.size() > 0) { if (log.isDebugEnabled()) { log.debug("Attempting to fetch the resource from the engaged extensions"); } for (RegistryExtension extension : extensions) { OMNode result = extension.lookup(key); if (result != null) { return result; } } } return null; } ByteArrayInputStream inputStream = null; Object content = resource.getContent(); if (content instanceof String) { inputStream = new ByteArrayInputStream(content.toString().getBytes()); } else if (content instanceof byte[]) { inputStream = new ByteArrayInputStream((byte[]) content); } OMNode result = null; try { XMLStreamReader parser = XMLInputFactory.newInstance(). createXMLStreamReader(inputStream); StAXOMBuilder builder = new StAXOMBuilder(parser); result = builder.getDocumentElement(); } catch (OMException ignored) { result = readNonXML(resource); } catch (XMLStreamException ignored) { result = readNonXML(resource); } catch (Exception e) { // a more general exception(e.g. a Runtime exception if the XML doc has an // external DTD deceleration and if not connected to internet) which in case // just log for debugging log.error("Error while reading the resource '" + key + "'", e); } finally { try { resource.discard(); if (result != null && result.getParent() != null) { result.detach(); OMDocumentImpl parent = new OMDocumentImpl(OMAbstractFactory.getOMFactory()); parent.addChild(result); } if (inputStream != null) { inputStream.close(); } } catch (IOException e) { log.error("Error while closing the input stream", e); } } return result; } catch (RegistryException e) { handleException("Error while fetching the resource " + key, e); } return null; } public OMNode lookupFormat(String key) { setTenantInfo(); if (key == null) { handleException("Resource cannot be found."); } if ("".equals(key)) { handleException("Resource cannot be empty"); } if (log.isDebugEnabled()) { log.debug("==> Repository fetch of resource with key : " + key); } try { Resource resource = getResource(key); if (resource instanceof Collection) { return null; } if (resource == null) { // try via available extensions if (extensions.size() > 0) { if (log.isDebugEnabled()) { log.debug("Attempting to fetch the resource from the engaged extensions"); } for (RegistryExtension extension : extensions) { OMNode result = extension.lookup(key); if (result != null) { return result; } } } return null; } ByteArrayInputStream inputStream = null; Object content = resource.getContent(); if (content instanceof String) { inputStream = new ByteArrayInputStream(content.toString().getBytes()); } else if (content instanceof byte[]) { inputStream = new ByteArrayInputStream((byte[]) content); } OMNode result = null; try { XMLStreamReader parser = XMLInputFactory.newInstance(). createXMLStreamReader(inputStream); StAXOMBuilder builder = new StAXOMBuilder(parser); result = builder.getDocumentElement(); } catch (OMException ignored) { result = readNonXML(resource); } catch (XMLStreamException ignored) { result = readNonXML(resource); } catch (Exception e) { // a more general exception(e.g. a Runtime exception if the XML doc has an // external DTD deceleration and if not connected to internet) which in case // just log for debugging log.error("Error while reading the resource '" + key + "'", e); } finally { try { resource.discard(); if (inputStream != null) { inputStream.close(); } } catch (IOException e) { log.error("Error while closing the input stream", e); } } return result; } catch (RegistryException e) { handleException("Error while fetching the resource " + key, e); } return null; } public void delete(String key) { setTenantInfo(); try { Registry registry = getRegistry(key); String resolvedPath = resolvePath(key); if (registry.resourceExists(resolvedPath)) { registry.delete(resolvedPath); } } catch (RegistryException e) { handleException("Error while deleting the resource at path :" + key, e); } } public void newResource(String key, boolean isDirectory) { setTenantInfo(); Registry registry = getRegistry(key); String resolvedKey = resolvePath(key); try { Resource resource; if (isDirectory) { resource = registry.newCollection(); } else { resource = registry.newResource(); } registry.put(resolvedKey, resource); } catch (RegistryException e) { handleException("Error while saving a resource at " + key, e); } } public void newNonEmptyResource(String key, boolean isDirectory, String mediaType, String content, String propertyName) { setTenantInfo(); Registry registry = getRegistry(key); String resolvedKey = resolvePath(key); try { Resource resource; if (isDirectory) { resource = registry.newCollection(); if (!propertyName.equals("")) { resource.setProperty(propertyName, content); } } else { resource = registry.newResource(); if (propertyName.equals("")){ resource.setMediaType(mediaType); resource.setContent(content); } else { resource.setProperty(propertyName, content); } } registry.put(resolvedKey, resource); } catch (RegistryException e) { handleException("Error while saving a resource at " + key, e); } } /** * Updates the content of a resource in the given path with given content * * @param path The resource path * @param value The resource content to be set */ public void updateResource(String path, Object value) { setTenantInfo(); Resource resource = getResource(path); if (resource != null) { Registry registry = getRegistry(path); if (value instanceof OMNode) { try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); XMLStreamWriter xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(baos); ((OMNode) value).serialize(xmlStreamWriter); resource.setContent(baos.toByteArray()); } catch (XMLStreamException e) { handleException("Error when serializing OMNode " + value, e); } catch (RegistryException e) { handleException("Error when setting content " + value, e); } } else { try { resource.setContent(value); } catch (RegistryException e) { handleException("Error when setting content " + value, e); } } try { registry.put(resource.getPath(), resource); resource.discard(); } catch (RegistryException e) { handleException("Error when setting a resource in the path : " + path, e); } } } public void updateRegistryEntry(RegistryEntry entry) { setTenantInfo(); String key = entry.getKey(); Resource resource = getResource(key); if (resource != null) { Registry registry = getRegistry(key); resource.setProperty(CACHABLE_DURATION, String.valueOf(entry.getCachableDuration())); resource.setProperty(EXPIRY_TIME, String.valueOf(System.currentTimeMillis() + entry.getCachableDuration())); try { registry.put(resource.getPath(), resource); resource.discard(); } catch (RegistryException e) { handleException("Error when setting a resource in the path : " + key, e); } } } public RegistryEntry getRegistryEntry(String entryKey) { setTenantInfo(); MediationRegistryEntryImpl entry = new MediationRegistryEntryImpl(); Resource resource = getResource(entryKey); if (resource != null) { entry.setKey(entryKey); entry.setName(resource.getPath()); if (resource instanceof Collection) { entry.setType(ESBRegistryConstants.FOLDER); } else { entry.setType(ESBRegistryConstants.FILE); } entry.setDescription("Resource at : " + resource.getPath()); entry.setLastModified(resource.getLastModified().getTime()); entry.setVersion(resource.getLastModified().getTime()); // Get root's cachable duration value long cacheTime = getCachableDuration(); String cachableDuration = resource.getProperty(CACHABLE_DURATION); if (cachableDuration != null) { // If the resource defines its own cachableDuration property, // override the value from root try { cacheTime = Long.parseLong(cachableDuration); } catch (NumberFormatException e) { handleException("Couldn't pass the cachableDuration as a long", e); } } entry.setCachableDuration(cacheTime); } else { // If the resource was found by an extension we need to set the // following properties for cachine to work entry.setKey(entryKey); entry.setCachableDuration(getCachableDuration()); } return entry; } public RegistryEntry[] getChildren(RegistryEntry entry) { setTenantInfo(); if (entry == null) { // give the children of the root // null or key = "" stands for root MediationRegistryEntryImpl registryEntry = new MediationRegistryEntryImpl(); registryEntry.setKey(rootPath); entry = registryEntry; } else { if ("".equals(entry.getKey())) { ((MediationRegistryEntryImpl) entry).setKey(rootPath); } } String parentPath; if (!entry.getKey().endsWith(RegistryConstants.PATH_SEPARATOR)) { parentPath = entry.getKey() + RegistryConstants.PATH_SEPARATOR; } else { parentPath = entry.getKey(); } Resource resource = getResource(entry.getKey()); if (resource == null) { return new RegistryEntry[]{new MediationRegistryEntryImpl()}; } if (resource instanceof Collection) { CollectionImpl collection = (CollectionImpl) resource; String[] children = new String[0]; try { children = collection.getChildren(); } catch (RegistryException e) { handleException("Error when retrieving children"); } List<RegistryEntry> entryList = new ArrayList<RegistryEntry>(); for (String child : children) { String key; if (child.endsWith(RegistryConstants.PATH_SEPARATOR)) { key = child.substring(0, child.length() - 1); } else { key = child; } Resource childResource = getResource(key); if (childResource == null) { continue; } MediationRegistryEntryImpl registryEntryEmbedded = new MediationRegistryEntryImpl(); registryEntryEmbedded.setKey(parentPath + RegistryUtils.getResourceName(key)); if (childResource instanceof Collection) { registryEntryEmbedded.setType(ESBRegistryConstants.FOLDER); } else { registryEntryEmbedded.setType(ESBRegistryConstants.FILE); } entryList.add(registryEntryEmbedded); } return entryList.toArray(new RegistryEntry[entryList.size()]); } else { ((MediationRegistryEntryImpl) entry).setType(ESBRegistryConstants.FILE); return new RegistryEntry[]{entry}; } } public RegistryEntry[] getDescendants(RegistryEntry entry) { setTenantInfo(); ArrayList<RegistryEntry> list = new ArrayList<RegistryEntry>(); RegistryEntry[] entries = getChildren(entry); if (entries != null) { for (RegistryEntry currentEntry : entries) { if (list.size() > MAX_KEYS) { break; } fillDescendants(currentEntry, list); } } RegistryEntry[] descendants = new RegistryEntry[list.size()]; for (int i = 0; i < list.size(); i++) { descendants[i] = list.get(i); } return descendants; } private void fillDescendants(RegistryEntry parent, ArrayList<RegistryEntry> list) { RegistryEntry[] entries = getChildren(parent); if (entries != null) { for (RegistryEntry entry : entries) { if (list.size() > MAX_KEYS) { break; } fillDescendants(entry, list); } } else { list.add(parent); } } public Resource getResource(String path) { setTenantInfo(); Registry registry = getRegistry(path); String key = resolvePath(path); try { if (registry.resourceExists(key)) { return registry.get(key); } } catch (RegistryException e) { handleException("Error while fetching the resource " + path, e); } return null; } /** * Returns all resource properties for a given registry resource * * @param entryKey - Registry path of the resource * @return Map of resource properties */ public Properties getResourceProperties(String entryKey) { setTenantInfo(); Resource resource = getResource(entryKey); if (resource != null) { Properties properties = new Properties(); Properties resourceProperties = resource.getProperties(); if (resourceProperties != null) { for (Object key : resourceProperties.keySet()) { Object value = resourceProperties.get(key); if (value instanceof List) { if (((List) value).size() > 0) { properties.put(key, ((List) value).get(0)); } } else { properties.put(key, value); } } } return properties; } return null; } private Registry getRegistry(String path) { if (path == null || "".equals(path) || path.startsWith(GOVERNANCE_REGISTRY_PREFIX)) { return governanceRegistry; } else if (path.startsWith(CONFIG_REGISTRY_PREFIX)) { return configRegistry; } else if (path.startsWith(LOCAL_REGISTRY_PREFIX)) { return localRegistry; } else { return governanceRegistry; } } private String resolvePath(String path) { if (path == null || "".equals(path)) { path = RegistryConstants.ROOT_PATH; } boolean governanceReg = false; if (path.startsWith(GOVERNANCE_REGISTRY_PREFIX)) { path = path.substring(GOVERNANCE_REGISTRY_PREFIX.length()); governanceReg = true; } else if (path.startsWith(CONFIG_REGISTRY_PREFIX)) { path = path.substring(CONFIG_REGISTRY_PREFIX.length()); } else if (path.startsWith(LOCAL_REGISTRY_PREFIX)) { path = path.substring(LOCAL_REGISTRY_PREFIX.length()); } else { governanceReg = true; } if (governanceReg && rootPath != null) { if (path.startsWith(RegistryConstants.PATH_SEPARATOR)) { path = path.substring(1); } path = rootPath + path; } return path; } /** * Helper method to handle non-XMl resources * * @param resource Registry resource * @return The content as an OMNode * @throws RegistryException if an error occurs while accessing the resource content */ private OMNode readNonXML(Resource resource) throws RegistryException { if (log.isDebugEnabled()) { log.debug("The resource at the specified path does not contain " + "well-formed XML - Processing as text"); } if (resource != null) { if (resource.getMediaType() == null || resource.getMediaType().equals("text/plain")) { // for non-xml text content or no media type defined return OMAbstractFactory.getOMFactory().createOMText(new String((byte[]) resource.getContent())); } //For media types other than text/plain ByteArrayInputStream inputStream = new ByteArrayInputStream((byte[]) resource.getContent()); try { OMFactory omFactory = OMAbstractFactory.getOMFactory(); return omFactory.createOMText( new DataHandler(new SynapseBinaryDataSource(inputStream, resource.getMediaType())), true); } catch (IOException e) { handleException("Error while getting a stream from resource content ", e); } finally { try { inputStream.close(); } catch (IOException e) { log.error("Error while closing the input stream", e); } } } return null; } private void registerExtension(String className) { try { Class clazz = this.getClass().getClassLoader().loadClass(className.trim()); RegistryExtension ext = (RegistryExtension) clazz.newInstance(); ext.init(properties); extensions.add(ext); } catch (Exception e) { handleException("Error while instantiating the registry extension " + "class : " + className, e); } } private long getCachableDuration() { String cachableDuration = (String) properties.get("cachableDuration"); return cachableDuration == null ? 0 : Long.parseLong(cachableDuration); } private void handleException(String msg, Exception e) { log.error(msg, e); throw new SynapseException(msg, e); } private void handleException(String msg) { log.error(msg); throw new SynapseException(msg); } /** * Carbon Kernel mandates to set Threadlocal before calling anything in kernel */ private void setTenantInfo() { // Preserve user name String username = PrivilegedCarbonContext.getThreadLocalCarbonContext().getUsername(); //Removing the below code segment due to empty stack exception coming from kernel //Current context does not need to be destroyed at this level. //PrivilegedCarbonContext.destroyCurrentContext(); PrivilegedCarbonContext cc = PrivilegedCarbonContext.getThreadLocalCarbonContext(); if (cc.getTenantDomain() == null) { cc.setTenantDomain(domain); } if (cc.getTenantId() == MultitenantConstants.INVALID_TENANT_ID) { cc.setTenantId(tenantId); } if (username != null) { // Set back the user name PrivilegedCarbonContext.getThreadLocalCarbonContext().setUsername(username); } } }