/*
* Copyright (c) WSO2 Inc. (http://wso2.com) 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.registry.extensions.internal;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.impl.builder.StAXOMBuilder;
import org.apache.commons.io.filefilter.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.osgi.service.component.ComponentContext;
import org.wso2.carbon.CarbonConstants;
import org.wso2.carbon.CarbonException;
import org.wso2.carbon.registry.common.utils.CommonUtil;
import org.wso2.carbon.registry.core.Collection;
import org.wso2.carbon.registry.core.Registry;
import org.wso2.carbon.registry.core.RegistryConstants;
import org.wso2.carbon.registry.core.config.RegistryContext;
import org.wso2.carbon.registry.core.exceptions.RegistryException;
import org.wso2.carbon.registry.core.jdbc.handlers.HandlerLifecycleManager;
import org.wso2.carbon.registry.core.jdbc.handlers.filters.URLMatcher;
import org.wso2.carbon.registry.core.service.RegistryService;
import org.wso2.carbon.registry.core.session.CurrentSession;
import org.wso2.carbon.registry.core.session.UserRegistry;
import org.wso2.carbon.registry.extensions.handlers.scm.ExternalContentHandler;
import org.wso2.carbon.utils.CarbonUtils;
import org.wso2.carbon.utils.multitenancy.MultitenantConstants;
import org.wso2.securevault.SecretResolver;
import org.wso2.securevault.SecretResolverFactory;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLStreamException;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Iterator;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.regex.Pattern;
/**
* @scr.component name="org.wso2.carbon.registry.scm" immediate="true"
* @scr.reference name="registry.service" interface="org.wso2.carbon.registry.core.service.RegistryService"
* cardinality="1..1" policy="dynamic" bind="setRegistryService" unbind="unsetRegistryService"
*/
@SuppressWarnings({"unused", "JavaDoc"})
public class RegistrySCMServiceComponent {
private static Log log = LogFactory.getLog(RegistrySCMServiceComponent.class);
private static final int DEFAULT_UPDATE_FREQUENCY = 60;
protected void activate(ComponentContext context) {
log.debug("Registry SCM component is activated");
}
protected void deactivate(ComponentContext context) {
log.debug("Registry SCM component is deactivated");
}
protected void setRegistryService(RegistryService registryService) {
try {
registerConnections(registryService);
} catch (RegistryException e) {
log.error("Unable to register connections", e);
}
}
protected void unsetRegistryService(RegistryService registryService) {
}
private void registerConnections(RegistryService registryService) throws RegistryException {
String configPath = CarbonUtils.getRegistryXMLPath();
if (configPath != null) {
File registryXML = new File(configPath);
if (registryXML.exists()) {
try {
CurrentSession.setCallerTenantId(MultitenantConstants.SUPER_TENANT_ID);
FileInputStream fileInputStream = new FileInputStream(registryXML);
StAXOMBuilder builder = new StAXOMBuilder(
CarbonUtils.replaceSystemVariablesInXml(fileInputStream));
OMElement configElement = builder.getDocumentElement();
SecretResolver secretResolver = SecretResolverFactory.create(configElement, false);
OMElement scm = configElement.getFirstChildWithName(new QName("scm"));
if (scm != null) {
ScheduledExecutorService executorService =
Executors.newScheduledThreadPool(10);
Iterator connections = scm.getChildrenWithName(new QName("connection"));
while (connections.hasNext()) {
OMElement connection = (OMElement) connections.next();
String checkOutURL =
connection.getAttributeValue(new QName("checkOutURL"));
// Read-Only by default, and can be disabled if needed by setting
// Read-Only to false.
boolean readOnly = !Boolean.toString(false).equalsIgnoreCase(
connection.getAttributeValue(new QName("readOnly")));
String checkInURL =
connection.getAttributeValue(new QName("checkInURL"));
String workingDir =
connection.getAttributeValue(new QName("workingDir"));
String mountPoint =
connection.getAttributeValue(new QName("mountPoint"));
String username =
connection.getFirstChildWithName(new QName("username")).getText();
String password =
connection.getFirstChildWithName(new QName("password")).getText();
int updateFrequency = DEFAULT_UPDATE_FREQUENCY;
try {
updateFrequency = Integer.parseInt(
connection.getAttributeValue(new QName("updateFrequency")));
} catch (NumberFormatException ignore) {
}
UserRegistry registry = registryService
.getRegistry(CarbonConstants.REGISTRY_SYSTEM_USERNAME);
File directory = new File(workingDir);
if (!directory.exists() && !directory.isDirectory()) {
log.error("A valid directory was not found in path: " + workingDir);
continue;
}
String filePath = directory.getAbsolutePath();
if (!registry.resourceExists(mountPoint)) {
Collection collection = registry.newCollection();
collection.setProperty(RegistryConstants.REGISTRY_NON_RECURSIVE,
"true");
registry.put(mountPoint, collection);
}
loadRegistryResources(registry, directory, filePath, mountPoint);
ExternalContentHandler externalContentHandler =
new ExternalContentHandler();
externalContentHandler.setFilePath(filePath);
externalContentHandler.setMountPath(mountPoint);
URLMatcher urlMatcher = new URLMatcher();
urlMatcher.setPattern(Pattern.quote(mountPoint) + "($|" +
RegistryConstants.PATH_SEPARATOR + ".*|" +
RegistryConstants.URL_SEPARATOR + ".*)");
RegistryContext registryContext = registry.getRegistryContext();
registryContext.registerNoCachePath(mountPoint);
registryContext.getHandlerManager().addHandler(null,
urlMatcher, externalContentHandler,
HandlerLifecycleManager.TENANT_SPECIFIC_SYSTEM_HANDLER_PHASE);
executorService.scheduleWithFixedDelay(new SCMUpdateTask(directory,
checkOutURL, checkInURL, readOnly, externalContentHandler,
username, CommonUtil.getResolvedPassword(secretResolver,"scm",password)), 0, updateFrequency, TimeUnit.MINUTES);
}
}
} catch (XMLStreamException e) {
log.error("Unable to parse registry.xml", e);
} catch (IOException e) {
log.error("Unable to read registry.xml", e);
} catch (CarbonException e) {
log.error("An error occurred during system variable replacement", e);
} finally {
CurrentSession.removeCallerTenantId();
}
}
}
}
private void loadRegistryResources(Registry registry, File directory, String workingDir,
String mountPoint) throws RegistryException {
File[] files = directory.listFiles((FileFilter) new AndFileFilter(HiddenFileFilter.VISIBLE,
new OrFileFilter(DirectoryFileFilter.INSTANCE, FileFileFilter.FILE)));
if (files == null) {
return;
}
for (File file : files) {
if (file.isDirectory()) {
loadRegistryResources(registry, file, workingDir, mountPoint);
} else {
// convert windows paths so that it fits into the Unix-like registry path structure.
String path = mountPoint +
file.getAbsolutePath().substring(workingDir.length()).replace("\\", "/");
if (!registry.resourceExists(path)) {
registry.put(path, registry.newResource());
}
}
}
}
}