Java tutorial
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF 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.apache.marmotta.platform.zookeeper.services; import at.salzburgresearch.nodekeeper.NodeKeeper; import at.salzburgresearch.nodekeeper.exception.NodeKeeperException; import org.apache.commons.lang.StringUtils; import org.apache.marmotta.platform.core.api.config.ConfigurationService; import org.apache.marmotta.platform.core.events.ConfigurationServiceInitEvent; import org.apache.marmotta.platform.zookeeper.api.ZookeeperService; import org.apache.marmotta.platform.zookeeper.event.ZookeeperInitEvent; import org.apache.marmotta.platform.zookeeper.listeners.ConfigurationListener; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.ZooDefs; import org.slf4j.Logger; import javax.annotation.PreDestroy; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.event.Event; import javax.enterprise.event.Observes; import javax.enterprise.inject.Any; import javax.inject.Inject; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.util.Properties; import java.util.UUID; /** * Add file description here! * * @author Sebastian Schaffert (sschaffert@apache.org) */ @ApplicationScoped public class ZookeeperServiceImpl implements ZookeeperService { @Inject private Logger log; @Inject private ConfigurationService configurationService; @Inject @Any private Event<ZookeeperInitEvent> zookeeperInitEvent; private NodeKeeper nodeKeeper; private Properties properties; private String datacenterIdPath; public void initialise(@Observes ConfigurationServiceInitEvent event) throws IOException, InterruptedException { log.warn("Activating Marmotta Zookeeper Bridge"); //read configuration final String connectionString = configurationService.getContextParam(ZK_SERVER); if (connectionString != null) { log.info(" - connection string: {}", connectionString); this.properties = new Properties(); File nkProperties = new File(configurationService.getHome() + File.separator + "nodekeeper.properties"); if (nkProperties.exists()) { properties.load(new FileInputStream(nkProperties)); } // get instance id (if not configured), first try from context parameters, if not given create random if (StringUtils.isBlank(configurationService.getStringConfiguration(ZK_INSTANCE))) { String instanceId; if (StringUtils.isBlank(configurationService.getContextParam(ZK_INSTANCE))) { instanceId = UUID.randomUUID().toString(); } else { instanceId = configurationService.getContextParam(ZK_INSTANCE); } configurationService.setConfiguration(ZK_INSTANCE, instanceId); } // get cluster name (if not configured), first try from context parameters, if not given use "default" if (StringUtils.isBlank(configurationService.getStringConfiguration(ZK_CLUSTER))) { String clusterId; if (StringUtils.isBlank(configurationService.getContextParam(ZK_CLUSTER))) { clusterId = "default"; } else { clusterId = configurationService.getContextParam(ZK_CLUSTER); } configurationService.setConfiguration(ZK_CLUSTER, clusterId); } log.info(" - initialize nodekeeper connection for instance {} (cluster {})", configurationService.getStringConfiguration(ZK_INSTANCE), configurationService.getStringConfiguration(ZK_CLUSTER)); try { nodeKeeper = new NodeKeeper(connectionString, configurationService.getIntConfiguration(ZK_TIMEOUT, 60000), properties, null); initZooKeeper(); String uuid = configurationService.getStringConfiguration(ZK_INSTANCE, UUID.randomUUID().toString()); String cluster = configurationService.getStringConfiguration(ZK_CLUSTER, "default"); ConfigurationListener listener = new ConfigurationListener(configurationService, nodeKeeper); nodeKeeper.addListener("/marmotta/config/[^/]+", listener); nodeKeeper.addListener(String.format("/marmotta/clusters/%s/config/[^/]+", cluster), listener); nodeKeeper.addListener( String.format("/marmotta/clusters/%s/instances/%s/config/[^/]+", cluster, uuid), listener); nodeKeeper.startListeners(); log.info("... running"); zookeeperInitEvent.fire(new ZookeeperInitEvent()); } catch (KeeperException ex) { log.error("could not initialise Zookeeper: {}", ex.getMessage()); } catch (NodeKeeperException e) { log.error("could not initialise NodeKeeper: {}", e.getMessage()); } } else { log.warn("no Zookeeper servers configured, Zookeeper Integration not available"); } } @PreDestroy private void shutdown() { try { log.info("ZOOKEEPER: deactivating Zookeeper Bridge ..."); if (nodeKeeper != null) { String cluster = configurationService.getStringConfiguration(ZK_CLUSTER, "default"); log.info("- removing lock on datacenter id"); nodeKeeper.getZooKeeper().delete(String.format(datacenterIdPath, cluster), -1); log.info(" - closing nodekeeper connection"); nodeKeeper.shutdown(); log.info(" ... closed"); } if (properties != null) { File nkProperties = new File( configurationService.getHome() + File.separator + "nodekeeper.properties"); properties.store(new FileOutputStream(nkProperties), "automatic nodekeeper state"); } } catch (InterruptedException | KeeperException | IOException e) { log.error("ZOOKEEPER: exception while shutting down Zookeeper connection ({})", e.getMessage()); } } /** * init zookeeper if necessary * @throws org.apache.zookeeper.KeeperException * @throws InterruptedException */ private void initZooKeeper() throws KeeperException, InterruptedException, IOException { if (nodeKeeper == null || nodeKeeper.getZooKeeper() == null) { log.error("ZooKeeper not available"); } else { String uuid = configurationService.getStringConfiguration(ZK_INSTANCE, UUID.randomUUID().toString()); String cluster = configurationService.getStringConfiguration(ZK_CLUSTER, "default"); //create base paths createNodeIfNotExists("/marmotta"); createNodeIfNotExists("/marmotta/config"); createNodeIfNotExists("/marmotta/clusters"); createNodeIfNotExists(String.format("/marmotta/clusters/%s", cluster)); createNodeIfNotExists(String.format("/marmotta/clusters/%s/config", cluster)); createNodeIfNotExists(String.format("/marmotta/clusters/%s/snowflake", cluster)); createNodeIfNotExists(String.format("/marmotta/clusters/%s/instances", cluster)); createNodeIfNotExists(String.format("/marmotta/clusters/%s/instances/%s", cluster, uuid)); createNodeIfNotExists(String.format("/marmotta/clusters/%s/instances/%s/config", cluster, uuid)); // TODO: check that the datacenter id is not yet occupied // configure datacenter id using a sequential ephemeral node datacenterIdPath = nodeKeeper.getZooKeeper().create( String.format("/marmotta/clusters/%s/snowflake/id-", cluster), new String("creator:" + uuid).getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL_SEQUENTIAL); int datacenterId = Integer.parseInt(datacenterIdPath.substring(datacenterIdPath.lastIndexOf("id-") + 3)) % 4096; log.info("ZOOKEEPER: generated datacenter ID {}", datacenterId); configurationService.setIntConfiguration("database.datacenter.id", datacenterId); } } private void createNodeIfNotExists(String path) throws KeeperException, InterruptedException { if (nodeKeeper.getZooKeeper().exists(path, false) == null) { String uuid = configurationService.getStringConfiguration(ZK_INSTANCE, UUID.randomUUID().toString()); nodeKeeper.getZooKeeper().create(path, new String("creator:" + uuid).getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT); } } }