Java tutorial
/** * Copyright 2005-2014 Red Hat, Inc. * * Red Hat 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 io.fabric8.git.http; import io.fabric8.api.FabricService; import io.fabric8.api.RuntimeProperties; import io.fabric8.api.TargetContainer; import io.fabric8.api.jcip.ThreadSafe; import io.fabric8.api.scr.AbstractComponent; import io.fabric8.api.scr.ValidatingReference; import io.fabric8.utils.Files; import io.fabric8.git.GitDataStore; import io.fabric8.git.GitHttpEndpoint; import io.fabric8.git.GitNode; import io.fabric8.groups.Group; import io.fabric8.groups.GroupListener; import io.fabric8.groups.internal.ZooKeeperGroup; import io.fabric8.zookeeper.ZkPath; import io.fabric8.zookeeper.utils.ZooKeeperUtils; import java.io.File; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collections; import java.util.Dictionary; import java.util.HashMap; import java.util.Hashtable; import java.util.Map; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import org.apache.curator.framework.CuratorFramework; import org.apache.felix.scr.annotations.Activate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.ConfigurationPolicy; import org.apache.felix.scr.annotations.Deactivate; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.Service; import org.eclipse.jgit.api.Git; import org.osgi.service.cm.ConfigurationAdmin; import org.osgi.service.http.HttpContext; import org.osgi.service.http.HttpService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @ThreadSafe @Component(name = "io.fabric8.git.server", label = "Fabric8 Git HTTP Server Registration Handler", policy = ConfigurationPolicy.OPTIONAL, immediate = true, metatype = true) @Service(GitHttpEndpoint.class) public final class GitHttpServerRegistrationHandler extends AbstractComponent implements GitHttpEndpoint, GroupListener<GitNode> { private static final Logger LOGGER = LoggerFactory.getLogger(GitHttpServerRegistrationHandler.class); private static final String REALM_PROPERTY_NAME = "realm"; private static final String ROLE_PROPERTY_NAME = "role"; private static final String DEFAULT_ROLE = "admin"; private static final Map<TargetContainer, String> defaultRealms; static { Map<TargetContainer, String> realms = new HashMap<TargetContainer, String>(); realms.put(TargetContainer.KARAF, "karaf"); realms.put(TargetContainer.TOMCAT, "fabric"); realms.put(TargetContainer.WILDFLY, "fabric-domain"); defaultRealms = Collections.unmodifiableMap(realms); } @Reference(referenceInterface = ConfigurationAdmin.class) private final ValidatingReference<ConfigurationAdmin> configAdmin = new ValidatingReference<ConfigurationAdmin>(); @Reference(referenceInterface = CuratorFramework.class) private final ValidatingReference<CuratorFramework> curator = new ValidatingReference<CuratorFramework>(); @Reference(referenceInterface = HttpService.class) private final ValidatingReference<HttpService> httpService = new ValidatingReference<HttpService>(); @Reference(referenceInterface = GitDataStore.class) private final ValidatingReference<GitDataStore> gitDataStore = new ValidatingReference<>(); @Reference(referenceInterface = RuntimeProperties.class) private final ValidatingReference<RuntimeProperties> runtimeProperties = new ValidatingReference<RuntimeProperties>(); //Reference not used, but it expresses the dependency on a fully initialized fabric. @Reference private FabricService fabricService; private final AtomicBoolean isMaster = new AtomicBoolean(); private final AtomicReference<String> gitRemoteUrl = new AtomicReference<>(); private Group<GitNode> group; private Path basePath; private Git git; private String realm; private String role; private Path dataPath; @Activate void activate(Map<String, ?> configuration) throws Exception { RuntimeProperties sysprops = runtimeProperties.get(); realm = getConfiguredRealm(sysprops, configuration); role = getConfiguredRole(sysprops, configuration); dataPath = sysprops.getDataPath(); activateComponent(); group = new ZooKeeperGroup<GitNode>(curator.get(), ZkPath.GIT.getPath(), GitNode.class); group.add(this); group.update(createState()); group.start(); } @Deactivate void deactivate() { deactivateComponent(); unregisterServlet(); try { if (group != null) { group.close(); } } catch (Exception e) { LOGGER.warn("Failed to remove git server from registry.", e); } } @Override public void groupEvent(Group<GitNode> group, GroupEvent event) { if (isValid()) { switch (event) { case CONNECTED: case CHANGED: updateMasterUrl(group); break; default: // do nothing } } } private String getConfiguredRealm(RuntimeProperties sysprops, Map<String, ?> configuration) { String realm = (String) configuration.get(REALM_PROPERTY_NAME); if (realm == null) { TargetContainer targetContainer = TargetContainer.getTargetContainer(sysprops); realm = defaultRealms.get(targetContainer); } return realm; } private String getConfiguredRole(RuntimeProperties sysprops, Map<String, ?> configuration) { return configuration.containsKey(ROLE_PROPERTY_NAME) ? (String) configuration.get(ROLE_PROPERTY_NAME) : DEFAULT_ROLE; } private void updateMasterUrl(Group<GitNode> group) { try { if (group.isMaster()) { LOGGER.debug("Git repo is the master"); if (!isMaster.getAndSet(true)) { registerServlet(dataPath, realm, role); } } else { LOGGER.debug("Git repo is not the master"); if (isMaster.getAndSet(false)) { unregisterServlet(); } } GitNode state = createState(); group.update(state); String url = state.getUrl(); gitRemoteUrl.set(ZooKeeperUtils.getSubstitutedData(curator.get(), url)); } catch (Exception e) { // Ignore } } private void registerServlet(Path dataPath, String realm, String role) throws Exception { synchronized (gitRemoteUrl) { basePath = dataPath.resolve(Paths.get("git", "servlet")); Path fabricRepoPath = basePath.resolve("fabric"); String servletBase = basePath.toFile().getAbsolutePath(); // Init and clone the local repo. File fabricRoot = fabricRepoPath.toFile(); if (!fabricRoot.exists()) { File localRepo = gitDataStore.get().getGit().getRepository().getDirectory(); git = Git.cloneRepository().setTimeout(10).setBare(true).setNoCheckout(true) .setCloneAllBranches(true).setDirectory(fabricRoot).setURI(localRepo.toURI().toString()) .call(); } else { git = Git.open(fabricRoot); } HttpContext base = httpService.get().createDefaultHttpContext(); HttpContext secure = new GitSecureHttpContext(base, curator.get(), realm, role); Dictionary<String, Object> initParams = new Hashtable<String, Object>(); initParams.put("base-path", servletBase); initParams.put("repository-root", servletBase); initParams.put("export-all", "true"); httpService.get().registerServlet("/git", new FabricGitServlet(git, curator.get()), initParams, secure); } } private void unregisterServlet() { synchronized (gitRemoteUrl) { if (basePath != null) { httpService.get().unregister("/git"); git.getRepository().close(); Files.recursiveDelete(basePath.toFile()); } } } private GitNode createState() { RuntimeProperties sysprops = runtimeProperties.get(); String runtimeIdentity = sysprops.getRuntimeIdentity(); GitNode state = new GitNode("fabric-repo", runtimeIdentity); if (group != null && group.isMaster()) { TargetContainer runtimeType = TargetContainer.getTargetContainer(sysprops); String context = runtimeType == TargetContainer.KARAF ? "" : "/fabric"; String fabricRepoUrl = "${zk:" + runtimeIdentity + "/http}" + context + "/git/fabric/"; state.setUrl(fabricRepoUrl); } return state; } void bindConfigAdmin(ConfigurationAdmin service) { this.configAdmin.bind(service); } void unbindConfigAdmin(ConfigurationAdmin service) { this.configAdmin.unbind(service); } void bindCurator(CuratorFramework curator) { this.curator.bind(curator); } void unbindCurator(CuratorFramework curator) { this.curator.unbind(curator); } void bindGitDataStore(GitDataStore service) { this.gitDataStore.bind(service); } void unbindGitDataStore(GitDataStore service) { this.gitDataStore.unbind(service); } void bindHttpService(HttpService service) { this.httpService.bind(service); } void unbindHttpService(HttpService service) { this.httpService.unbind(service); } void bindRuntimeProperties(RuntimeProperties service) { this.runtimeProperties.bind(service); } void unbindRuntimeProperties(RuntimeProperties service) { this.runtimeProperties.unbind(service); } }