Java tutorial
/** * Copyright (C) 2015 The Gravitee team (http://gravitee.io) * * 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 * * 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.gravitee.gateway.services.localregistry; import io.gravitee.common.service.AbstractService; import io.gravitee.common.utils.IdGenerator; import io.gravitee.definition.jackson.datatype.GraviteeMapper; import io.gravitee.gateway.handlers.api.definition.Api; import io.gravitee.gateway.handlers.api.manager.ApiManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import java.io.File; import java.io.IOException; import java.nio.file.*; import java.util.HashMap; import java.util.Map; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; /** * @author David BRASSELY (brasseld at gmail.com) */ public class LocalApiDefinitionRegistry extends AbstractService { private static final Logger LOGGER = LoggerFactory.getLogger(LocalApiDefinitionRegistry.class); private static final String JSON_EXTENSION = ".json"; @Value("${services.local.enabled:false}") private boolean enabled; @Value("${services.local.path:${gravitee.home}/apis}") private String registryPath; @Autowired private ApiManager apiManager; private ExecutorService executor; private Map<Path, Api> definitions = new HashMap<>(); /** * Empty constructor is used to use a workspace directory defined from @Value annotation * on registryPath field. */ public LocalApiDefinitionRegistry() { } public LocalApiDefinitionRegistry(String registryPath) { this.registryPath = registryPath; } private void init() { if (enabled) { if (registryPath == null || registryPath.isEmpty()) { LOGGER.error("Local API definitions registry path is not specified."); throw new RuntimeException("Local API definitions registry path is not specified."); } File registryDir = new File(registryPath); // Quick sanity check on the install root if (!registryDir.isDirectory()) { LOGGER.error("Invalid API definitions registry directory, {} is not a directory.", registryDir.getAbsolutePath()); throw new RuntimeException("Invalid API definitions registry directory. Not a directory: " + registryDir.getAbsolutePath()); } initRegistry(registryDir); } else { LOGGER.warn("Local registry for API definitions is disabled"); } } private void initRegistry(File registryDir) { LOGGER.info("Loading API definitions from {}", registryDir.getAbsoluteFile()); File[] definitionFiles = searchForDefinitions(registryDir); LOGGER.info("\t{} API definitions have been found.", definitionFiles.length); for (File definitionFile : definitionFiles) { try { Api api = loadDefinition(definitionFile); apiManager.deploy(api); definitions.put(Paths.get(definitionFile.toURI()), api); } catch (IOException e) { LOGGER.error("Unable to load API definition from {}", definitionFile, e); } } } private File[] searchForDefinitions(File registryDir) { return registryDir.listFiles((dir, name) -> name.endsWith(JSON_EXTENSION)); } private Api loadDefinition(File apiDefinitionFile) throws IOException { Api api = new GraviteeMapper().readValue(apiDefinitionFile, Api.class); api.setId(IdGenerator.generate(api.getName())); return api; } @Override protected void doStart() throws Exception { if (enabled) { super.doStart(); this.init(); executor = Executors.newSingleThreadExecutor(r -> new Thread(r, "registry-monitor")); executor.execute(() -> { Path registry = Paths.get(registryPath); LOGGER.info("Start local registry monitor for directory {}", registry); try { WatchService watcher = registry.getFileSystem().newWatchService(); registry.register(watcher, StandardWatchEventKinds.ENTRY_CREATE, StandardWatchEventKinds.ENTRY_DELETE, StandardWatchEventKinds.ENTRY_MODIFY); while (true) { WatchKey key; try { key = watcher.take(); } catch (InterruptedException ex) { return; } for (WatchEvent<?> event : key.pollEvents()) { WatchEvent.Kind<?> kind = event.kind(); @SuppressWarnings("unchecked") WatchEvent<Path> ev = (WatchEvent<Path>) event; Path fileName = registry.resolve(ev.context().getFileName()); LOGGER.info("An event occurs for file {}: {}", fileName, kind.name()); if (kind == StandardWatchEventKinds.ENTRY_MODIFY) { Api loadedDefinition = loadDefinition(fileName.toFile()); Api existingDefinition = definitions.get(fileName); if (existingDefinition != null) { if (apiManager.get(existingDefinition.getId()) != null) { apiManager.update(loadedDefinition); } else { apiManager.undeploy(existingDefinition.getId()); definitions.remove(fileName); apiManager.deploy(loadedDefinition); definitions.put(fileName, loadedDefinition); } } } else if (kind == StandardWatchEventKinds.ENTRY_CREATE) { Api loadedDefinition = loadDefinition(fileName.toFile()); Api existingDefinition = apiManager.get(loadedDefinition.getId()); if (existingDefinition != null) { apiManager.update(loadedDefinition); } else { apiManager.deploy(loadedDefinition); definitions.put(fileName, loadedDefinition); } } else if (kind == StandardWatchEventKinds.ENTRY_DELETE) { Api existingDefinition = definitions.get(fileName); if (existingDefinition != null && apiManager.get(existingDefinition.getId()) != null) { apiManager.undeploy(existingDefinition.getId()); definitions.remove(fileName); } } boolean valid = key.reset(); if (!valid) { break; } } } } catch (IOException ioe) { LOGGER.error("Unexpected error while looking for PI definitions from filesystem", ioe); } }); } } @Override protected void doStop() throws Exception { if (enabled) { super.doStop(); executor.shutdownNow(); executor = null; } } public void setApiManager(ApiManager apiManager) { this.apiManager = apiManager; } public void setEnabled(boolean enabled) { this.enabled = enabled; } public void setRegistryPath(String registryPath) { this.registryPath = registryPath; } }