diff --git a/cesium-plus-pod-assembly/src/test/es-home/config/logging.yml b/cesium-plus-pod-assembly/src/test/es-home/config/logging.yml index 9963d24c4caa4f672f11dcd7113bc22fe81bb61c..033d8a1510bddfe11a21074467be9dcf374ea202 100644 --- a/cesium-plus-pod-assembly/src/test/es-home/config/logging.yml +++ b/cesium-plus-pod-assembly/src/test/es-home/config/logging.yml @@ -16,7 +16,7 @@ logger: duniter: DEBUG #duniter.core: DEBUG - #duniter.security: ERROR + duniter.security: WARN #duniter.user.event: DEBUG #duniter.network.p2p: DEBUG #duniter.network.peer: DEBUG diff --git a/cesium-plus-pod-core/pom.xml b/cesium-plus-pod-core/pom.xml index 957f5f8b390432f0b09056a1ed0bf34098b0b20e..009d4c7fa02c53fec52a1fe7e9e026a2892b5ad3 100644 --- a/cesium-plus-pod-core/pom.xml +++ b/cesium-plus-pod-core/pom.xml @@ -79,7 +79,7 @@ <dependency> <groupId>org.antlr</groupId> - <artifactId>stringtemplate</artifactId> + <artifactId>ST4</artifactId> <version>${stringtemplate.version}</version> <scope>compile</scope> </dependency> diff --git a/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/PluginInit.java b/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/PluginInit.java index f9c4b8413aa995511a4ae84d99dede041b6371ea..969c6f8884ca0f516a0da8984e6bdec713d80053 100644 --- a/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/PluginInit.java +++ b/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/PluginInit.java @@ -152,6 +152,10 @@ public class PluginInit extends AbstractLifecycleComponent<PluginInit> { } final String currencyName = currency.getCurrencyName(); + peer.setCurrency(currencyName); + + // Define the main peer for this currency (will fill a cache in PeerService) + injector.getInstance(PeerService.class).setCurrencyMainPeer(currencyName, peer); // Add access security rules, for the currency indices injector.getInstance(RestSecurityController.class) diff --git a/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/PluginSettings.java b/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/PluginSettings.java index a8b04f7c257440f64d7970d48a30f4d7f6a0ce29..be1812a4799437e6dfae66fe66ca847afc5474a9 100644 --- a/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/PluginSettings.java +++ b/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/PluginSettings.java @@ -286,11 +286,25 @@ public class PluginSettings extends AbstractLifecycleComponent<PluginSettings> { return this.settings.getAsBoolean("duniter.p2p.peering.enable", enableSynchro()); } + /** + * Peer endpoint API to index (into the '_currency_/peer') + * @return + */ + public Collection<EndpointApi> getPeerIndexedApis() { + String[] includeApis = settings.getAsArray("duniter.p2p.peer.indexedApis"); + // By default: getPeeringPublishedApis + getPeeringTargetedApis + if (CollectionUtils.isEmpty(includeApis)) { + return CollectionUtils.union(getPeeringTargetedApis(), getPeeringPublishedApis()); + } + + return Arrays.stream(includeApis).map(EndpointApi::valueOf).collect(Collectors.toList()); + } + /** * Endpoint API to publish, in the emitted peer document. By default, plugins will defined their own API * @return */ - public List<EndpointApi> getPeeringPublishedApis() { + public Collection<EndpointApi> getPeeringPublishedApis() { String[] targetedApis = settings.getAsArray("duniter.p2p.peering.publishedApis"); if (CollectionUtils.isEmpty(targetedApis)) return null; @@ -302,7 +316,7 @@ public class PluginSettings extends AbstractLifecycleComponent<PluginSettings> { * This API should accept a POST request to '/network/peering' (like Duniter node, but can also be a pod) * @return */ - public List<EndpointApi> getPeeringTargetedApis() { + public Collection<EndpointApi> getPeeringTargetedApis() { String[] targetedApis = settings.getAsArray("duniter.p2p.peering.targetedApis", new String[]{ EndpointApi.BASIC_MERKLED_API.name(), EndpointApi.BMAS.name() diff --git a/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/dao/impl/PeerDaoImpl.java b/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/dao/impl/PeerDaoImpl.java index bc9c77611f2b41da14a39432d9f56eab11be8bb7..9b7ede0d13dec9a014d4ff0ae102ae8086e37801 100644 --- a/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/dao/impl/PeerDaoImpl.java +++ b/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/dao/impl/PeerDaoImpl.java @@ -23,6 +23,7 @@ package org.duniter.elasticsearch.dao.impl; */ import com.fasterxml.jackson.core.JsonProcessingException; +import com.google.common.collect.ImmutableList; import org.duniter.core.client.model.bma.EndpointApi; import org.duniter.core.client.model.local.Peer; import org.duniter.core.exception.TechnicalException; @@ -143,7 +144,8 @@ public class PeerDaoImpl extends AbstractDao implements PeerDao { @Override public List<Peer> getPeersByCurrencyId(String currencyId) { - throw new TechnicalException("no implemented: loading all peers may be unsafe for memory..."); + logger.warn("Calling method PeerSevice.getPeersByCurrencyId() may be unsafe, as it load all peers in memory. Applying workaround: return peer define in config."); + return ImmutableList.of(pluginSettings.checkAndGetPeer()); } @Override @@ -372,6 +374,11 @@ public class PeerDaoImpl extends AbstractDao implements PeerDao { //.field("dynamic", "false") .startObject("properties") + // stats.software + .startObject(Peer.Stats.PROPERTY_SOFTWARE) + .field("type", "string") + .endObject() + // stats.version .startObject(Peer.Stats.PROPERTY_VERSION) .field("type", "string") diff --git a/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/rest/RestModule.java b/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/rest/RestModule.java index 0a872252d3cd6c6c5933b539b462124037e02c08..193fe0b318edb05fe6b07ccfab08cdb539e76b3a 100644 --- a/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/rest/RestModule.java +++ b/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/rest/RestModule.java @@ -23,6 +23,8 @@ package org.duniter.elasticsearch.rest; */ import org.duniter.elasticsearch.rest.attachment.RestImageAttachmentAction; +import org.duniter.elasticsearch.rest.blockchain.RestBlockchainBlockGetAction; +import org.duniter.elasticsearch.rest.blockchain.RestBlockchainParametersGetAction; import org.duniter.elasticsearch.rest.network.RestNetworkPeeringGetAction; import org.duniter.elasticsearch.rest.network.RestNetworkPeeringPostAction; import org.duniter.elasticsearch.rest.node.RestNodeSummaryGetAction; @@ -56,6 +58,9 @@ public class RestModule extends AbstractModule implements Module { bind(RestNetworkPeeringGetAction.class).asEagerSingleton(); bind(RestNetworkPeeringPostAction.class).asEagerSingleton(); + // Blockchain + bind(RestBlockchainParametersGetAction.class).asEagerSingleton(); + bind(RestBlockchainBlockGetAction.class).asEagerSingleton(); } } \ No newline at end of file diff --git a/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/rest/blockchain/RestBlockchainBlockGetAction.java b/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/rest/blockchain/RestBlockchainBlockGetAction.java new file mode 100644 index 0000000000000000000000000000000000000000..e8c4c434f2eef30b9334d0baf41ea2446c87a3ab --- /dev/null +++ b/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/rest/blockchain/RestBlockchainBlockGetAction.java @@ -0,0 +1,103 @@ +package org.duniter.elasticsearch.rest.blockchain; + +/* + * #%L + * duniter4j-elasticsearch-plugin + * %% + * Copyright (C) 2014 - 2016 EIS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.http.entity.ContentType; +import org.duniter.core.client.config.Configuration; +import org.duniter.core.client.model.bma.BlockchainBlock; +import org.duniter.core.client.model.bma.jackson.JacksonUtils; +import org.duniter.core.exception.TechnicalException; +import org.duniter.core.util.StringUtils; +import org.duniter.elasticsearch.PluginSettings; +import org.duniter.elasticsearch.rest.AbstractRestPostIndexAction; +import org.duniter.elasticsearch.rest.XContentRestResponse; +import org.duniter.elasticsearch.rest.security.RestSecurityController; +import org.duniter.elasticsearch.service.BlockchainService; +import org.duniter.elasticsearch.service.CurrencyService; +import org.elasticsearch.client.Client; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.xcontent.XContentBuilder; +import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.rest.*; + +import java.io.IOException; + +/** + * A rest to post a request to process a new currency/peer. + * + */ +public class RestBlockchainBlockGetAction extends BaseRestHandler { + + private BlockchainService blockchainService; + + @Inject + public RestBlockchainBlockGetAction(Settings settings, RestController controller, Client client, RestSecurityController securityController, + BlockchainService blockchainService) { + super(settings, controller, client); + + securityController.allow(RestRequest.Method.GET, "(/[^/]+)?/blockchain/block/[0-9]+"); + securityController.allow(RestRequest.Method.GET, "(/[^/]+)?/blockchain/current"); + + controller.registerHandler(RestRequest.Method.GET, "/blockchain/block/{number}", this); + controller.registerHandler(RestRequest.Method.GET, "/blockchain/current", this); + controller.registerHandler(RestRequest.Method.GET, "/{index}/blockchain/block/{number}", this); + controller.registerHandler(RestRequest.Method.GET, "/{index}/blockchain/current", this); + + this.blockchainService = blockchainService; + } + + @Override + protected void handleRequest(RestRequest request, RestChannel channel, Client client) throws Exception { + String currency = request.param("index"); + int number = request.paramAsInt("number", -1); + boolean isCurrent = (number == -1); + + BlockchainBlock block; + if (isCurrent) { + block = blockchainService.getCurrentBlock(currency); + } + else { + block = blockchainService.getBlockById(currency, number); + } + + try { + channel.sendResponse(new BytesRestResponse(RestStatus.OK, + ContentType.APPLICATION_JSON.toString(), + getObjectMapper() + .writerWithDefaultPrettyPrinter() + .writeValueAsString(block))); + } + catch(IOException ioe) { + if (isCurrent) + throw new TechnicalException(String.format("Error while generating JSON for [/blockchain/current]: %s", ioe.getMessage()), ioe); + else + throw new TechnicalException(String.format("Error while generating JSON for [/blockchain/block/%s]: %s", number, ioe.getMessage()), ioe); + } + } + + protected ObjectMapper getObjectMapper() { + return JacksonUtils.getThreadObjectMapper(); + } +} \ No newline at end of file diff --git a/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/rest/blockchain/RestBlockchainParametersGetAction.java b/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/rest/blockchain/RestBlockchainParametersGetAction.java new file mode 100644 index 0000000000000000000000000000000000000000..2e5bb15f8b8701ffc9b69588c259cd19185ea9fa --- /dev/null +++ b/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/rest/blockchain/RestBlockchainParametersGetAction.java @@ -0,0 +1,82 @@ +package org.duniter.elasticsearch.rest.blockchain; + +/* + * #%L + * duniter4j-elasticsearch-plugin + * %% + * Copyright (C) 2014 - 2016 EIS + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program. If not, see + * <http://www.gnu.org/licenses/gpl-3.0.html>. + * #L% + */ + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.http.entity.ContentType; +import org.duniter.core.client.model.bma.BlockchainBlock; +import org.duniter.core.client.model.bma.BlockchainParameters; +import org.duniter.core.client.model.bma.jackson.JacksonUtils; +import org.duniter.core.exception.TechnicalException; +import org.duniter.elasticsearch.rest.security.RestSecurityController; +import org.duniter.elasticsearch.service.BlockchainService; +import org.elasticsearch.client.Client; +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.rest.*; + +import java.io.IOException; + +/** + * A rest to post a request to process a new currency/peer. + * + */ +public class RestBlockchainParametersGetAction extends BaseRestHandler { + + private BlockchainService blockchainService; + + @Inject + public RestBlockchainParametersGetAction(Settings settings, RestController controller, Client client, RestSecurityController securityController, + BlockchainService blockchainService) { + super(settings, controller, client); + + securityController.allow(RestRequest.Method.GET, "(/[^/]+)?/blockchain/parameters"); + + controller.registerHandler(RestRequest.Method.GET, "/blockchain/parameters", this); + controller.registerHandler(RestRequest.Method.GET, "/{index}/blockchain/parameters", this); + + this.blockchainService = blockchainService; + } + + @Override + protected void handleRequest(RestRequest request, RestChannel channel, Client client) throws Exception { + + String currency = request.param("index"); + BlockchainParameters parameters = blockchainService.getParameters(currency); + + try { + channel.sendResponse(new BytesRestResponse(RestStatus.OK, + ContentType.APPLICATION_JSON.toString(), + getObjectMapper() + .writerWithDefaultPrettyPrinter() + .writeValueAsString(parameters))); + } + catch(IOException ioe) { + throw new TechnicalException(String.format("Error while generating JSON for [/blockchain/parameters]: %s", ioe.getMessage()), ioe); + } + } + + protected ObjectMapper getObjectMapper() { + return JacksonUtils.getThreadObjectMapper(); + } +} \ No newline at end of file diff --git a/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/rest/network/RestNetworkPeeringPostAction.java b/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/rest/network/RestNetworkPeeringPostAction.java index 16e3719e95d533c712abea74d6d5440c2d1aa4b1..8d9d6d28a03df879feff4f20bf6c7bbbe9f57782 100644 --- a/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/rest/network/RestNetworkPeeringPostAction.java +++ b/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/rest/network/RestNetworkPeeringPostAction.java @@ -89,7 +89,7 @@ public class RestNetworkPeeringPostAction extends BaseRestHandler { String peerDocument = content.getProperty("peer"); if (StringUtils.isBlank(peerDocument)) { - throw new TechnicalException("Inavlid request: 'peer' property not found"); + throw new TechnicalException("Invalid request: 'peer' property not found"); } // Decode content diff --git a/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/service/BlockchainService.java b/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/service/BlockchainService.java index a0dc8c6c2cf3b0f539af5306f294f06bd8cf5a29..ec22a81156ef613951aa5f9077face5b7f4b586b 100644 --- a/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/service/BlockchainService.java +++ b/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/service/BlockchainService.java @@ -26,6 +26,7 @@ package org.duniter.elasticsearch.service; import com.google.common.base.Objects; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Lists; +import org.duniter.core.client.dao.CurrencyDao; import org.duniter.core.client.model.bma.BlockchainBlock; import org.duniter.core.client.model.bma.BlockchainParameters; import org.duniter.core.client.model.bma.EndpointApi; @@ -33,6 +34,8 @@ import org.duniter.core.client.model.local.Peer; import org.duniter.core.client.service.bma.BlockchainRemoteService; import org.duniter.core.client.service.bma.NetworkRemoteService; import org.duniter.core.client.service.exception.BlockNotFoundException; +import org.duniter.core.client.util.KnownBlocks; +import org.duniter.core.client.util.KnownCurrencies; import org.duniter.core.exception.TechnicalException; import org.duniter.core.model.NullProgressionModel; import org.duniter.core.model.ProgressionModel; @@ -41,22 +44,20 @@ import org.duniter.core.util.CollectionUtils; import org.duniter.core.util.ObjectUtils; import org.duniter.core.util.Preconditions; import org.duniter.core.util.StringUtils; +import org.duniter.core.util.cache.Cache; +import org.duniter.core.util.cache.SimpleCache; import org.duniter.core.util.json.JsonAttributeParser; import org.duniter.core.util.websocket.WebsocketClientEndpoint; import org.duniter.elasticsearch.PluginSettings; import org.duniter.elasticsearch.client.Duniter4jClient; import org.duniter.elasticsearch.dao.BlockDao; +import org.duniter.elasticsearch.dao.CurrencyExtendDao; import org.duniter.elasticsearch.exception.DuplicateIndexIdException; import org.duniter.elasticsearch.threadpool.ThreadPool; -import org.elasticsearch.action.admin.cluster.node.info.NodesInfoAction; -import org.elasticsearch.action.admin.cluster.node.info.NodesInfoRequestBuilder; -import org.elasticsearch.action.admin.cluster.node.info.NodesInfoResponse; -import org.elasticsearch.action.admin.cluster.node.info.TransportNodesInfoAction; import org.elasticsearch.action.bulk.BulkItemResponse; import org.elasticsearch.action.bulk.BulkRequestBuilder; import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.common.inject.Inject; -import org.elasticsearch.rest.action.admin.cluster.node.info.RestNodesInfoAction; import org.nuiton.i18n.I18n; import java.io.IOException; @@ -67,6 +68,7 @@ import java.util.*; */ public class BlockchainService extends AbstractService { + private static final BlockchainBlock DEFAULT_BLOCK = KnownBlocks.getFirstBlock(KnownCurrencies.G1); public static final String BLOCK_TYPE = BlockDao.TYPE; public static final String CURRENT_BLOCK_ID = "current"; @@ -83,17 +85,21 @@ public class BlockchainService extends AbstractService { private final JsonAttributeParser<String> blockHashParser = new JsonAttributeParser<>("hash", String.class); private final JsonAttributeParser<String> blockPreviousHashParser = new JsonAttributeParser<>("previousHash", String.class); + private SimpleCache<String, BlockchainParameters> blockchainParametersCurrencyIdCache; private BlockDao blockDao; + private CurrencyExtendDao currencyDao; @Inject public BlockchainService(Duniter4jClient client, PluginSettings settings, ThreadPool threadPool, BlockDao blockDao, + CurrencyDao currencyDao, final ServiceLocator serviceLocator){ super("duniter.blockchain", client, settings); this.client = client; this.blockDao = blockDao; + this.currencyDao = (CurrencyExtendDao) currencyDao; threadPool.scheduleOnStarted(() -> { blockchainRemoteService = serviceLocator.getBlockchainRemoteService(); setIsReady(true); @@ -112,6 +118,13 @@ public class BlockchainService extends AbstractService { } } }; + blockchainParametersCurrencyIdCache = new SimpleCache<String, BlockchainParameters>(/*eternal*/) { + @Override + public BlockchainParameters load(String currencyId) { + if (!isReady()) throw new IllegalStateException("Could not load blockchain parameters (service is not started)"); + return blockchainRemoteService.getParameters(currencyId); + } + }; } @@ -466,12 +479,35 @@ public class BlockchainService extends AbstractService { } } - public BlockchainBlock getBlockById(final String currencyName, final int number) { - return blockDao.getBlockById(currencyName, String.valueOf(number)); + public BlockchainBlock getBlockById(String currency, final int number) { + + // Retrieve the currency to use + boolean enableBlockchainIndexation = pluginSettings.enableBlockchainIndexation() && currencyDao.existsIndex(); + if (StringUtils.isBlank(currency)) { + List<String> currencyIds = enableBlockchainIndexation ? currencyDao.getCurrencyIds() : null; + if (CollectionUtils.isNotEmpty(currencyIds)) { + currency = currencyIds.get(0); + } else { + currency = DEFAULT_BLOCK.getCurrency(); + } + } + + return blockDao.getBlockById(currency, String.valueOf(number)); } - public BlockchainBlock getCurrentBlock(final String currencyName) { - return blockDao.getBlockById(currencyName, CURRENT_BLOCK_ID); + public BlockchainBlock getCurrentBlock(String currency) { + // Retrieve the currency to use + boolean enableBlockchainIndexation = pluginSettings.enableBlockchainIndexation() && currencyDao.existsIndex(); + if (StringUtils.isBlank(currency)) { + List<String> currencyIds = enableBlockchainIndexation ? currencyDao.getCurrencyIds() : null; + if (CollectionUtils.isNotEmpty(currencyIds)) { + currency = currencyIds.get(0); + } else { + currency = DEFAULT_BLOCK.getCurrency(); + } + } + + return blockDao.getBlockById(currency, CURRENT_BLOCK_ID); } public void deleteFrom(final String currencyName, final int fromBlock) { @@ -539,6 +575,26 @@ public class BlockchainService extends AbstractService { return missingBlockNumbers; } + public BlockchainParameters getParameters(String currency) { + // Check in cache + if (StringUtils.isNotBlank(currency)) { + return blockchainParametersCurrencyIdCache.get(currency); + } + + // Or get default + BlockchainParameters result = blockchainParametersCurrencyIdCache.getIfPresent("DEFAULT"); + + // Or fill default using duniter node + if (result == null && pluginSettings.enableBlockchainIndexation()) { + Peer peer = pluginSettings.checkAndGetPeer(); + result = blockchainRemoteService.getParameters(peer); + blockchainParametersCurrencyIdCache.put(result.getCurrency(), result); + blockchainParametersCurrencyIdCache.put("DEFAULT", result); + } + + return result; + } + private Collection<String> indexBlocksUsingBulk(Peer peer, String currencyName, int firstNumber, int lastNumber, ProgressionModel progressionModel, boolean isLastCurrentNumber) { Set<String> missingBlockNumbers = new LinkedHashSet<>(); diff --git a/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/service/CurrencyService.java b/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/service/CurrencyService.java index 0323203a874d6fc4fd0e492095c0d9cf4e2a7324..a7c3b7506ba700a2ec113e2bb5f128ecfb9f73e1 100644 --- a/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/service/CurrencyService.java +++ b/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/service/CurrencyService.java @@ -214,8 +214,8 @@ public class CurrencyService extends AbstractService { createIndexRequestBuilder.addMapping(blockDao.getType(), blockDao.createTypeMapping()); // Add movement type - MovementDao operationDao = ServiceLocator.instance().getBean(MovementDao.class); - createIndexRequestBuilder.addMapping(operationDao.getType(), operationDao.createTypeMapping()); + MovementDao movementDao = ServiceLocator.instance().getBean(MovementDao.class); + createIndexRequestBuilder.addMapping(movementDao.getType(), movementDao.createTypeMapping()); // Add blockStat type BlockStatDao blockStatDao = injector.getInstance(BlockStatDao.class); diff --git a/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/service/NetworkService.java b/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/service/NetworkService.java index ebf295c64cbe94537e5739f2e684554a9085fa15..45c444a53907122e1e8063d17d7da8ca30672c22 100644 --- a/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/service/NetworkService.java +++ b/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/service/NetworkService.java @@ -49,6 +49,7 @@ import org.elasticsearch.common.inject.Inject; import java.io.IOException; import java.util.*; +import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -73,6 +74,7 @@ public class NetworkService extends AbstractService { private HttpService httpService; private NetworkRemoteService networkRemoteService; private PeerService peerService; + private final boolean debug; @Inject public NetworkService(Duniter4jClient client, @@ -91,6 +93,7 @@ public class NetworkService extends AbstractService { this.blockchainService = blockchainService; this.peerService = peerService; this.threadPool = threadPool; + this.debug = logger.isDebugEnabled(); threadPool.scheduleOnStarted(() -> { this.httpService = serviceLocator.getHttpService(); this.networkRemoteService = serviceLocator.getNetworkRemoteService(); @@ -142,7 +145,7 @@ public class NetworkService extends AbstractService { } } catch (IOException e) { - if (logger.isDebugEnabled()) { + if (debug) { logger.warn(String.format("Unable to parse P2P endpoint [%s]: %s", endpoint, e.getMessage()), e); } else { @@ -400,7 +403,7 @@ public class NetworkService extends AbstractService { peering = NetworkPeerings.parse(peeringDocument); } catch(Exception e) { - throw new TechnicalException("Inavlid peer document: " + e.getMessage(), e); + throw new TechnicalException("Invalid peer document: " + e.getMessage(), e); } // Check validity then save @@ -424,22 +427,26 @@ public class NetworkService extends AbstractService { Peer peer = Peer.newBuilder() .setCurrency(peering.getCurrency()) .setPubkey(peering.getPubkey()) - .setEndpoint(ep).build(); - EndpointApi api = EndpointApi.valueOf(peer.getApi()); - peers.add(peer); + .setEndpoint(ep) + .build(); + + Peer.Stats stats = new Peer.Stats(); + peer.setStats(stats); - // TODO: filter to keep only useful API ? - //if (targetPeersEndpointApis.contains(api)) { - // peers.add(peer); - //} - //else { - // logger.debug(String.format("Ignoring endpoint {%s}: not a targeted API", peer)); - //} + String blockStamp = peering.getBlock(); + if (StringUtils.isNotBlank(blockStamp)) { + String[] blockParts = blockStamp.split("-"); + stats.setBlockNumber(Integer.parseInt(blockParts[0])); + stats.setBlockHash(blockParts[1]); + } + + peers.add(peer); } - // Save peers - if (CollectionUtils.isEmpty(peers)) { - peerService.save(peering.getCurrency(), peers, false); + // Save peers (if not empty) + if (CollectionUtils.isNotEmpty(peers)) { + if (debug) logger.debug("Saving peers: " + peers.toString()); + peerService.save(peering.getCurrency(), peers, false, true, true); } return peering; @@ -528,12 +535,12 @@ public class NetworkService extends AbstractService { } - protected void addAllTargetPeerEndpointApis(List<EndpointApi> apis) { + protected void addAllTargetPeerEndpointApis(Collection<EndpointApi> apis) { Preconditions.checkNotNull(apis); apis.forEach(this::addTargetPeerEndpointApi); } - protected void addAllPublishEndpointApis(List<EndpointApi> apis) { + protected void addAllPublishEndpointApis(Collection<EndpointApi> apis) { Preconditions.checkNotNull(apis); apis.forEach(this::addPublishEndpointApi); } diff --git a/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/service/PeerService.java b/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/service/PeerService.java index 166d411737612ba1fdd689003207d0a2ec9f12fa..234acae391a03ba27bf91d951d0bcd61ba71fc17 100644 --- a/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/service/PeerService.java +++ b/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/service/PeerService.java @@ -24,7 +24,7 @@ package org.duniter.elasticsearch.service; import com.google.common.collect.ImmutableList; -import com.google.common.collect.Lists; +import com.google.common.collect.Sets; import org.duniter.core.client.dao.PeerDao; import org.duniter.core.client.model.bma.BlockchainParameters; import org.duniter.core.client.model.bma.EndpointApi; @@ -39,7 +39,10 @@ import org.duniter.elasticsearch.threadpool.ThreadPool; import org.elasticsearch.common.inject.Inject; import org.nuiton.i18n.I18n; +import java.util.Collection; import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; /** * Created by Benoit on 30/03/2015. @@ -53,10 +56,8 @@ public class PeerService extends AbstractService { private ThreadPool threadPool; // Define endpoint API to include - private static List<String> includeEndpointApis = Lists.newArrayList( - EndpointApi.BASIC_MERKLED_API.name(), - EndpointApi.BMAS.name(), - EndpointApi.WS2P.name()); + // API to include inside when getting peers + private final static Set<String> indexedEndpointApis = Sets.newHashSet(); @Inject public PeerService(Duniter4jClient client, PluginSettings settings, ThreadPool threadPool, @@ -71,22 +72,29 @@ public class PeerService extends AbstractService { this.delegate = serviceLocator.getPeerService(); setIsReady(true); }); + + // If filtered API defined in settings, use it + if (CollectionUtils.isNotEmpty(pluginSettings.getPeerIndexedApis())) { + addAllPeerIndexedEndpointApis(pluginSettings.getPeerIndexedApis()); + } } - public PeerService addIncludeEndpointApi(String api) { + public PeerService addIndexedEndpointApi(String api) { Preconditions.checkNotNull(api); - if (!includeEndpointApis.contains(api)) { - includeEndpointApis.add(api); - } + if (!indexedEndpointApis.contains(api)) indexedEndpointApis.add(api); return this; } - public PeerService addIncludeEndpointApi(EndpointApi api) { + public PeerService addIndexedEndpointApi(EndpointApi api) { Preconditions.checkNotNull(api); - addIncludeEndpointApi(api.name()); + addIndexedEndpointApi(api.name()); return this; } + public void setCurrencyMainPeer(String currency, Peer peer) { + delegate.setCurrencyMainPeer(currency, peer); + } + public PeerService indexPeers(Peer peer) { try { @@ -117,7 +125,7 @@ public class PeerService extends AbstractService { org.duniter.core.client.service.local.NetworkService.Filter filterDef = new org.duniter.core.client.service.local.NetworkService.Filter(); filterDef.filterType = null; filterDef.filterStatus = Peer.PeerStatus.UP; - filterDef.filterEndpoints = ImmutableList.copyOf(includeEndpointApis); + filterDef.filterEndpoints = ImmutableList.copyOf(indexedEndpointApis); // Default sort org.duniter.core.client.service.local.NetworkService.Sort sortDef = new org.duniter.core.client.service.local.NetworkService.Sort(); @@ -137,7 +145,31 @@ public class PeerService extends AbstractService { delegate.save(peer); } - public void save(final String currencyId, final List<Peer> peers, boolean isFullList) { + public void save(final String currencyId, final List<Peer> peers, boolean isFullList, boolean applyFilterEndpoints, boolean refreshPeers) { + // Skip if empty and NOT the full list + if (!isFullList && CollectionUtils.isEmpty(peers)) return; + + // Filter on endpoint apis + if (applyFilterEndpoints) { + List<Peer> filteredPeers = peers.stream().filter(p -> indexedEndpointApis.contains(p.getApi())).collect(Collectors.toList()); + save(currencyId, filteredPeers, isFullList, false, refreshPeers); // Loop, without applying filter + return; + } + + if (refreshPeers) { + final Peer mainPeer = pluginSettings.checkAndGetPeer(); + + // Async refresh + networkService.asyncRefreshPeers(mainPeer, peers, threadPool.scheduler()) + .exceptionally(throwable -> { + logger.error("Could not refresh peers status: " + throwable.getMessage(), throwable); + return peers; + }) + // then loop, without refreshing + .thenAccept(list -> save(currencyId, list, isFullList, false, false)); + return; + } + delegate.save(currencyId, peers, isFullList); } @@ -154,7 +186,7 @@ public class PeerService extends AbstractService { NetworkService.Filter filterDef = new NetworkService.Filter(); filterDef.filterType = null; filterDef.filterStatus = Peer.PeerStatus.UP; - filterDef.filterEndpoints = ImmutableList.copyOf(includeEndpointApis); + filterDef.filterEndpoints = ImmutableList.copyOf(indexedEndpointApis); filterDef.currency = currencyName; // Default sort @@ -169,4 +201,9 @@ public class PeerService extends AbstractService { public Long getMaxLastUpTime(String currencyId) { return peerDao.getMaxLastUpTime(currencyId); } + + protected void addAllPeerIndexedEndpointApis(Collection<EndpointApi> apis) { + Preconditions.checkNotNull(apis); + apis.forEach(this::addIndexedEndpointApi); + } } diff --git a/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/threadpool/ThreadPool.java b/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/threadpool/ThreadPool.java index 06689ebafa78951bde7f7be57a0cc5849633acf8..f83a140fb5ecc56b52c4cff6eefd37dab74e2e6f 100644 --- a/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/threadpool/ThreadPool.java +++ b/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/threadpool/ThreadPool.java @@ -80,7 +80,7 @@ public class ThreadPool extends AbstractLifecycleComponent<ThreadPool> { public void doStart(){ if (logger.isDebugEnabled()) { - logger.debug("Starting Duniter4j ThreadPool..."); + logger.debug("Starting thread pool..."); } if (!afterStartedCommands.isEmpty()) { diff --git a/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/util/springtemplate/STUtils.java b/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/util/springtemplate/STUtils.java index cd0cb61b9f40bc0a38a92d411daa633c35253073..a56b5ff4d13bf08fb2cbebbb03820b6bc37e2699 100644 --- a/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/util/springtemplate/STUtils.java +++ b/cesium-plus-pod-core/src/main/java/org/duniter/elasticsearch/util/springtemplate/STUtils.java @@ -1,9 +1,7 @@ package org.duniter.elasticsearch.util.springtemplate; -import org.stringtemplate.v4.DateRenderer; import org.stringtemplate.v4.STGroup; import org.stringtemplate.v4.STGroupDir; -import org.stringtemplate.v4.StringRenderer; import java.util.Date; diff --git a/cesium-plus-pod-subscription/pom.xml b/cesium-plus-pod-subscription/pom.xml index 266d6f8d64dcdff8e92fa14f2975276e3779ac5f..173963cf23aae95aeef6b7a2411e0c32933b6c20 100644 --- a/cesium-plus-pod-subscription/pom.xml +++ b/cesium-plus-pod-subscription/pom.xml @@ -44,7 +44,7 @@ <dependency> <groupId>org.antlr</groupId> - <artifactId>stringtemplate</artifactId> + <artifactId>ST4</artifactId> <version>${stringtemplate.version}</version> <scope>provided</scope> </dependency> diff --git a/cesium-plus-pod-subscription/src/main/java/org/duniter/elasticsearch/subscription/PluginSettings.java b/cesium-plus-pod-subscription/src/main/java/org/duniter/elasticsearch/subscription/PluginSettings.java index 4a2aba7308ab674b0fddea9343a9f31c47663601..e6ba1ee8190fb40ee8452eb0c7ce92e1f8fe957e 100644 --- a/cesium-plus-pod-subscription/src/main/java/org/duniter/elasticsearch/subscription/PluginSettings.java +++ b/cesium-plus-pod-subscription/src/main/java/org/duniter/elasticsearch/subscription/PluginSettings.java @@ -28,6 +28,7 @@ import org.duniter.core.util.crypto.KeyPair; import org.elasticsearch.common.component.*; import org.elasticsearch.common.inject.Inject; +import java.util.Collection; import java.util.List; /** @@ -146,11 +147,11 @@ public class PluginSettings extends AbstractLifecycleComponent<PluginSettings> { return delegate.enablePeering(); } - public List<EndpointApi> getPeeringTargetedApis() { + public Collection<EndpointApi> getPeeringTargetedApis() { return this.delegate.getPeeringTargetedApis(); } - public List<EndpointApi> getPeeringPublishedApis() { + public Collection<EndpointApi> getPeeringPublishedApis() { return this.delegate.getPeeringPublishedApis(); } diff --git a/cesium-plus-pod-subscription/src/main/java/org/duniter/elasticsearch/subscription/service/SubscriptionService.java b/cesium-plus-pod-subscription/src/main/java/org/duniter/elasticsearch/subscription/service/SubscriptionService.java index 45d1048674d233446dce2c1e2a87da9adc2dac11..55c730927f4e834e1b16e7ab45eff85e14209315 100644 --- a/cesium-plus-pod-subscription/src/main/java/org/duniter/elasticsearch/subscription/service/SubscriptionService.java +++ b/cesium-plus-pod-subscription/src/main/java/org/duniter/elasticsearch/subscription/service/SubscriptionService.java @@ -27,7 +27,6 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.google.common.collect.ImmutableSet; import org.duniter.core.client.model.ModelUtils; -import org.duniter.core.client.model.bma.jackson.JacksonUtils; import org.duniter.core.client.model.elasticsearch.Record; import org.duniter.core.exception.TechnicalException; import org.duniter.core.service.CryptoService; @@ -43,8 +42,6 @@ import org.duniter.elasticsearch.subscription.dao.record.SubscriptionRecordDao; import org.duniter.elasticsearch.subscription.model.SubscriptionExecution; import org.duniter.elasticsearch.subscription.model.SubscriptionRecord; import org.duniter.elasticsearch.subscription.model.email.EmailSubscription; -import org.duniter.elasticsearch.subscription.util.stringtemplate.DateRenderer; -import org.duniter.elasticsearch.subscription.util.stringtemplate.StringRenderer; import org.duniter.elasticsearch.threadpool.ThreadPool; import org.duniter.elasticsearch.user.model.UserEvent; import org.duniter.elasticsearch.user.service.AdminService; @@ -57,7 +54,6 @@ import org.elasticsearch.common.unit.TimeValue; import org.nuiton.i18n.I18n; import org.stringtemplate.v4.ST; import org.stringtemplate.v4.STGroup; -import org.stringtemplate.v4.STGroupDir; import java.text.SimpleDateFormat; import java.util.*; @@ -78,6 +74,7 @@ public class SubscriptionService extends AbstractService { private UserService userService; private String emailSubjectPrefix; private STGroup templates; + private boolean debug; @Inject public SubscriptionService(Duniter4jClient client, @@ -102,8 +99,10 @@ public class SubscriptionService extends AbstractService { if (StringUtils.isNotBlank(emailSubjectPrefix)) { emailSubjectPrefix += " "; // add one trailing space } + this.debug = logger.isDebugEnabled(); // Configure springtemplate engine + STGroup.verbose = debug; templates = STUtils.newSTGroup("org/duniter/elasticsearch/subscription/templates"); Preconditions.checkNotNull(templates.getInstanceOf("text_email"), "Missing ST template {text_email}"); Preconditions.checkNotNull(templates.getInstanceOf("html_email_content"), "Missing ST template {html_email_content}"); @@ -269,19 +268,19 @@ public class SubscriptionService extends AbstractService { boolean debug = pluginSettings.isEmailSubscriptionsDebug(); if (subscription.getContent() != null && subscription.getContent().getEmail() != null) { if (debug) { - logger.info(String.format("Processing email subscription to [%s - %s] on account [%s]", + logger.info(String.format("Processing email subscription from {%s} to {%s} (pubkey: %s)", senderName, subscription.getContent().getEmail(), ModelUtils.minifyPubkey(subscription.getIssuer()))); } else { - logger.info(String.format("Processing email subscription [%s] on account [%s]", + logger.info(String.format("Processing email subscription to {%s} (pubkey: %s)", subscription.getId(), ModelUtils.minifyPubkey(subscription.getIssuer()))); } } else { - logger.warn(String.format("Processing email subscription [%s] - no email found in subscription content: skipping", subscription.getId())); + logger.warn(String.format("Processing email subscription {id=%s}: no email found in content. Skipping", subscription.getId())); return null; } @@ -313,9 +312,7 @@ public class SubscriptionService extends AbstractService { // Get user locale String[] localParts = subscription.getContent() != null && subscription.getContent().getLocale() != null ? subscription.getContent().getLocale().split("-") : new String[]{"en", "GB"}; - Locale issuerLocale = localParts.length >= 2 ? new Locale(localParts[0].toLowerCase(), localParts[1].toUpperCase()) : new Locale(localParts[0].toLowerCase()); - - + Locale userLocale = localParts.length >= 2 ? new Locale(localParts[0].toLowerCase(), localParts[1].toUpperCase()) : new Locale(localParts[0].toLowerCase()); // Compute text content final String text = fillTemplate( @@ -325,8 +322,9 @@ public class SubscriptionService extends AbstractService { senderName, profileTitles, userEvents, + userLocale, pluginSettings.getEmailLinkUrl()) - .render(issuerLocale); + .render(userLocale); // Compute HTML content final String html = fillTemplate( @@ -336,8 +334,9 @@ public class SubscriptionService extends AbstractService { senderName, profileTitles, userEvents, + userLocale, pluginSettings.getEmailLinkUrl()) - .render(issuerLocale); + .render(userLocale); final String object = emailSubjectPrefix + I18n.t("duniter4j.es.subscription.email.subject", userEvents.size()); if (pluginSettings.isEmailSubscriptionsDebug()) { @@ -370,12 +369,13 @@ public class SubscriptionService extends AbstractService { } - public static ST fillTemplate(ST template, + public static ST fillTemplate(final ST template, EmailSubscription subscription, String senderPubkey, String senderName, Map<String, String> issuerProfilNames, List<UserEvent> userEvents, + final Locale issuerLocale, String cesiumSiteUrl) { String issuerName = issuerProfilNames != null && issuerProfilNames.containsKey(subscription.getIssuer()) ? issuerProfilNames.get(subscription.getIssuer()) : @@ -393,11 +393,9 @@ public class SubscriptionService extends AbstractService { template.add("senderPubkey", senderPubkey); template.add("senderName", senderName); userEvents.forEach(userEvent -> { - String description = userEvent.getParams() != null ? - I18n.t("duniter.user.event." + userEvent.getCode().toUpperCase(), userEvent.getParams()) : - I18n.t("duniter.user.event." + userEvent.getCode().toUpperCase()); + String description = getUserEventDescription(issuerLocale, userEvent); template.addAggr("events.{description, time}", new Object[]{ - description, + description, new Date(userEvent.getTime() * 1000) }); }); @@ -451,5 +449,42 @@ public class SubscriptionService extends AbstractService { } } + private static String getUserEventDescription(Locale locale, UserEvent userEvent) { + final String defaultKey = "duniter.user.event." + userEvent.getCode().toUpperCase(); + + // Retrieve the translated description: prefer 'duniter.<INDEX>.event.<CODE>' if exists, + // and 'duniter.user.event.<CODE>' otherwise + final UserEvent.Reference reference = userEvent.getReference(); + if (reference != null && reference.getIndex() != null) { + return firstValidI18n(locale, + new String[]{ + String.format("duniter.%s.%s.event.%s", userEvent.getReference().getIndex().toLowerCase(), userEvent.getReference().getType().toLowerCase(), userEvent.getCode().toUpperCase()), + String.format("duniter.%s.event.%s", userEvent.getReference().getIndex().toLowerCase(), userEvent.getCode().toUpperCase()), + defaultKey + }, + userEvent.getParams()); + } + + return userEvent.getParams() != null ? + I18n.l(locale, defaultKey, userEvent.getParams()) : + I18n.l(locale, defaultKey); + } + /** + * Return the first valid i18N translation + * @param locale + * @param keys + * @param params + * @return + */ + private static String firstValidI18n(Locale locale, String[] keys, String[] params) { + String result = null; + for (String key: keys) { + result = params != null ? I18n.l(locale, key, params) : I18n.l(locale, key); + if (!key.equals(result)) { + return result; + } + } + return result; + } } diff --git a/cesium-plus-pod-subscription/src/main/java/org/duniter/elasticsearch/subscription/util/stringtemplate/DateRenderer.java b/cesium-plus-pod-subscription/src/main/java/org/duniter/elasticsearch/subscription/util/stringtemplate/DateRenderer.java deleted file mode 100644 index 9fb695d17a0636af3a21bfc5d6fc1bb43bca2ad9..0000000000000000000000000000000000000000 --- a/cesium-plus-pod-subscription/src/main/java/org/duniter/elasticsearch/subscription/util/stringtemplate/DateRenderer.java +++ /dev/null @@ -1,65 +0,0 @@ -package org.duniter.elasticsearch.subscription.util.stringtemplate; - -/*- - * #%L - * Duniter4j :: ElasticSearch Subscription plugin - * %% - * Copyright (C) 2014 - 2017 EIS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - -import org.stringtemplate.v4.AttributeRenderer; - -import java.text.DateFormat; -import java.text.SimpleDateFormat; -import java.util.*; - -public class DateRenderer implements AttributeRenderer { - - public DateRenderer() { - } - - public String toString(Object o, String formatString, Locale locale) { - if(formatString == null) { - formatString = "short"; - } - - Date d; - if(o instanceof Calendar) { - d = ((Calendar)o).getTime(); - } else { - d = (Date)o; - } - - Integer styleI = (Integer)org.stringtemplate.v4.DateRenderer.formatToInt.get(formatString); - Object f; - if(styleI == null) { - f = new SimpleDateFormat(formatString, locale); - } else { - int style = styleI.intValue(); - if(formatString.startsWith("date:")) { - f = DateFormat.getDateInstance(style, locale); - } else if(formatString.startsWith("time:")) { - f = DateFormat.getTimeInstance(style, locale); - } else { - f = DateFormat.getDateTimeInstance(style, style, locale); - } - } - - return ((DateFormat)f).format(d); - } -} \ No newline at end of file diff --git a/cesium-plus-pod-subscription/src/main/java/org/duniter/elasticsearch/subscription/util/stringtemplate/StringRenderer.java b/cesium-plus-pod-subscription/src/main/java/org/duniter/elasticsearch/subscription/util/stringtemplate/StringRenderer.java deleted file mode 100644 index fdbda8bdad3ba14d55f3e2bc0dc31f4cb20e4288..0000000000000000000000000000000000000000 --- a/cesium-plus-pod-subscription/src/main/java/org/duniter/elasticsearch/subscription/util/stringtemplate/StringRenderer.java +++ /dev/null @@ -1,54 +0,0 @@ -package org.duniter.elasticsearch.subscription.util.stringtemplate; - -/*- - * #%L - * Duniter4j :: ElasticSearch Subscription plugin - * %% - * Copyright (C) 2014 - 2017 EIS - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * <http://www.gnu.org/licenses/gpl-3.0.html>. - * #L% - */ - -import org.duniter.core.client.model.ModelUtils; -import org.duniter.core.util.CollectionUtils; -import org.duniter.core.util.StringUtils; -import org.nuiton.i18n.I18n; -import org.stringtemplate.v4.AttributeRenderer; - -import java.util.Locale; - -/** - * Add format capabilities: i18n, pubkey - * Created by blavenie on 10/04/17. - */ -public class StringRenderer extends org.stringtemplate.v4.StringRenderer{ - - @Override - public String toString(Object o, String formatString, Locale locale) { - return formatString == null ? (String)o : - (formatString.equals("pubkey") ? ModelUtils.minifyPubkey((String)o) : - (formatString.startsWith("i18n") ? toI18nString(o, formatString, locale) : - super.toString(o, formatString, locale))); - } - - protected String toI18nString(Object key, String formatString, Locale locale) { - String[] params = formatString.startsWith("i18n:") ? formatString.substring(5).split(",") : null; - if (CollectionUtils.isNotEmpty(params)) { - return I18n.l(locale, key.toString(), params); - } - return I18n.l(locale, key.toString()); - } -} diff --git a/cesium-plus-pod-subscription/src/test/java/org/duniter/elasticsearch/subscription/service/SubscriptionTemplateTest.java b/cesium-plus-pod-subscription/src/test/java/org/duniter/elasticsearch/subscription/service/SubscriptionTemplateTest.java index 33932a39e2e83c0da74097cec9210e2d52d8c15d..94a0689f67be545b696581a5da378b21ac957701 100644 --- a/cesium-plus-pod-subscription/src/test/java/org/duniter/elasticsearch/subscription/service/SubscriptionTemplateTest.java +++ b/cesium-plus-pod-subscription/src/test/java/org/duniter/elasticsearch/subscription/service/SubscriptionTemplateTest.java @@ -24,14 +24,12 @@ package org.duniter.elasticsearch.subscription.service; import org.duniter.core.client.model.ModelUtils; import org.duniter.core.exception.TechnicalException; -import org.duniter.elasticsearch.subscription.util.stringtemplate.DateRenderer; -import org.duniter.elasticsearch.subscription.util.stringtemplate.StringRenderer; +import org.duniter.elasticsearch.util.springtemplate.STUtils; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.stringtemplate.v4.ST; import org.stringtemplate.v4.STGroup; -import org.stringtemplate.v4.STGroupDir; import java.util.Date; import java.util.Locale; @@ -44,16 +42,13 @@ import static org.junit.Assert.assertNotNull; public class SubscriptionTemplateTest { private static final Logger log = LoggerFactory.getLogger(SubscriptionTemplateTest.class); - private static final boolean verbose = false; + private static final boolean verbose = true; @Test public void testHtmlEmail() throws Exception{ try { - STGroup group = new STGroupDir("templates", '$', '$'); - - group.registerRenderer(Date.class, new DateRenderer()); - group.registerRenderer(String.class, new StringRenderer()); + STGroup group = STUtils.newSTGroup("org/duniter/elasticsearch/subscription/templates"); ST tpl = group.getInstanceOf("html_email_content"); tpl.add("issuerName", "MyIssuerName"); @@ -80,10 +75,7 @@ public class SubscriptionTemplateTest { public void testTextEmail() throws Exception{ try { - STGroup group = new STGroupDir("templates", '$', '$'); - - group.registerRenderer(Date.class, new DateRenderer()); - group.registerRenderer(String.class, new StringRenderer()); + STGroup group = STUtils.newSTGroup("org/duniter/elasticsearch/subscription/templates"); ST tpl = group.getInstanceOf("text_email"); tpl.add("issuerPubkey", "5ocqzyDMMWf1V8bsoNhWb1iNwax1e9M7VTUN6navs8of"); diff --git a/cesium-plus-pod-user/src/main/java/org/duniter/elasticsearch/user/PluginSettings.java b/cesium-plus-pod-user/src/main/java/org/duniter/elasticsearch/user/PluginSettings.java index 823bae9d37101a80e5fa20163d307a3abd116a5c..fdc05f1b3a43a7c579ea4a815212c76dc68d6030 100644 --- a/cesium-plus-pod-user/src/main/java/org/duniter/elasticsearch/user/PluginSettings.java +++ b/cesium-plus-pod-user/src/main/java/org/duniter/elasticsearch/user/PluginSettings.java @@ -29,7 +29,7 @@ import org.elasticsearch.common.component.AbstractLifecycleComponent; import org.elasticsearch.common.inject.Inject; import org.elasticsearch.common.settings.Settings; -import java.util.List; +import java.util.Collection; import java.util.Locale; /** @@ -98,11 +98,11 @@ public class PluginSettings extends AbstractLifecycleComponent<PluginSettings> { return this.delegate.enablePeering(); } - public List<EndpointApi> getPeeringTargetedApis() { + public Collection<EndpointApi> getPeeringTargetedApis() { return this.delegate.getPeeringTargetedApis(); } - public List<EndpointApi> getPeeringPublishedApis() { + public Collection<EndpointApi> getPeeringPublishedApis() { return this.delegate.getPeeringPublishedApis(); } diff --git a/pom.xml b/pom.xml index ad0d71fada06368eafb7221e2a58bbfb603e51fd..c95d1d8adc3ddce529b648658c5815727fa94580 100644 --- a/pom.xml +++ b/pom.xml @@ -29,7 +29,7 @@ <signatureVersion>1.0</signatureVersion> <!-- Commons versions --> - <duniter4j.version>1.1.0</duniter4j.version> + <duniter4j.version>1.1.1</duniter4j.version> <log4j.version>1.2.17</log4j.version> <slf4j.version>1.7.6</slf4j.version> <guava.version>22.0</guava.version> @@ -41,7 +41,7 @@ <jna.version>4.2.0</jna.version><!--4.3.0 could not build --> <tyrus.version>1.14</tyrus.version> <jackson.version>2.9.5</jackson.version> - <stringtemplate.version>4.0.2</stringtemplate.version> + <stringtemplate.version>4.1</stringtemplate.version> <jTextUtilsVersion>0.3.3</jTextUtilsVersion> <nuitonConfigVersion>3.0</nuitonConfigVersion> @@ -166,7 +166,7 @@ <dependency> <groupId>org.duniter</groupId> <artifactId>duniter4j-core-client</artifactId> - <version>1.1.0</version> + <version>${duniter4j.version}</version> </dependency> <dependency> @@ -196,7 +196,7 @@ </dependency> <dependency> <groupId>org.antlr</groupId> - <artifactId>stringtemplate</artifactId> + <artifactId>ST4</artifactId> <version>${stringtemplate.version}</version> <exclusions> <exclusion>