Tony CHEMIT pushed to branch develop at ultreiaio / ird-observe Commits: 58a78780 by Tony Chemit at 2023-11-23T13:58:02+01:00 update pom - - - - - 5171ad36 by Tony Chemit at 2023-11-25T13:40:12+01:00 update pom change pom dependencies coordinates - - - - - b474e869 by Tony Chemit at 2023-11-25T13:40:12+01:00 Remove never used code - - - - - b009e471 by Tony Chemit at 2023-11-25T13:40:12+01:00 fix on service should be PUT but was POST... - - - - - e810ab41 by Tony Chemit at 2023-11-25T13:40:12+01:00 Update http library API and improve timeout tuning - - - - - 40a629ff by Tony Chemit at 2023-11-25T13:40:12+01:00 add missing annotations - - - - - 8fbbb17f by Tony Chemit at 2023-11-25T14:47:48+01:00 Upgrade to fileupload2 - - - - - bc7ebe50 by Tony Chemit at 2023-11-25T14:47:48+01:00 update pom - - - - - bdc2aff0 by Tony Chemit at 2023-11-25T14:48:58+01:00 Merge branch 'feature/issue-2605' into develop Mettre à jour la libraire apache http-client - Closes #2605 - - - - - 25 changed files: - core/api/services/src/main/java/fr/ird/observe/services/service/data/ps/AvdthService.java - core/services/client/pom.xml - core/services/client/src/main/java/fr/ird/observe/services/client/ObserveRequestBuilder.java - core/services/client/src/main/java/fr/ird/observe/services/client/ObserveServiceFactoryClient.java - pom.xml - server/configuration/src/main/resources/log4j2.xml - server/core/src/main/filtered-resources/META-INF/mapping-api-client.wm - server/core/src/main/java/fr/ird/observe/server/ObserveWebApplicationListener.java - server/core/src/main/java/fr/ird/observe/server/request/ObserveWebRequestContext.java - server/runner/src/main/resources/META-INF/configuration/log.xml - toolkit/api-services/src/main/java/fr/ird/observe/services/service/AnonymousService.java - toolkit/api-services/src/main/java/fr/ird/observe/services/service/UsageService.java - toolkit/api-services/src/main/java/fr/ird/observe/services/service/api/DataEntityService.java - toolkit/api-services/src/main/java/fr/ird/observe/services/service/api/ReferentialEntityService.java - toolkit/plugin/src/main/java/fr/ird/observe/toolkit/maven/plugin/service/ServiceGenerateApiRunner.java - toolkit/plugin/src/main/java/fr/ird/observe/toolkit/maven/plugin/service/ServiceLocalMethodDescriptionImpl.java - toolkit/server/pom.xml - toolkit/server/src/main/java/org/debux/webmotion/server/call/ServerContext.java - toolkit/server/src/main/java/org/debux/webmotion/server/handler/ExecutorMethodInvokerHandler.java - toolkit/server/src/main/java/org/debux/webmotion/server/handler/ExecutorParametersInjectorHandler.java - toolkit/server/src/main/java/org/debux/webmotion/server/handler/ParametersMultipartHandler.java - toolkit/server/src/main/java/org/debux/webmotion/server/call/FileProgressListener.java → toolkit/server/src/main/java/org/debux/webmotion/server/tools/upload/FileProgressListener.java - + toolkit/server/src/main/java/org/debux/webmotion/server/tools/upload/FileUpload.java - toolkit/server/src/main/java/org/debux/webmotion/server/tools/StringResponseHandler.java → toolkit/server/src/main/java/org/debux/webmotion/server/tools/upload/RequestContext.java - toolkit/server/src/main/resources/META-INF/web-fragment.xml Changes: ===================================== core/api/services/src/main/java/fr/ird/observe/services/service/data/ps/AvdthService.java ===================================== @@ -25,6 +25,7 @@ package fr.ird.observe.services.service.data.ps; import fr.ird.observe.datasource.security.Permission; import fr.ird.observe.services.service.MethodCredential; import fr.ird.observe.services.service.ObserveService; +import io.ultreia.java4all.http.spi.Get; import io.ultreia.java4all.http.spi.Service; /** @@ -42,6 +43,7 @@ public interface AvdthService extends ObserveService { * @param configuration configuration of import * @return result of import. */ + @Get @MethodCredential(Permission.READ_ALL_AND_WRITE_DATA) AvdthDataImportResult importData(AvdthDataImportConfiguration configuration) throws MissingReferentialException; ===================================== core/services/client/pom.xml ===================================== @@ -102,8 +102,12 @@ <artifactId>commons-lang3</artifactId> </dependency> <dependency> - <groupId>org.apache.httpcomponents</groupId> - <artifactId>httpcore</artifactId> + <groupId>org.apache.httpcomponents.client5</groupId> + <artifactId>httpclient5</artifactId> + </dependency> + <dependency> + <groupId>org.apache.httpcomponents.core5</groupId> + <artifactId>httpcore5</artifactId> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> @@ -163,22 +167,6 @@ <groupId>commons-fileupload</groupId> <artifactId>commons-fileupload</artifactId> </exclusion> - <exclusion> - <groupId>commons-collections</groupId> - <artifactId>commons-collections</artifactId> - </exclusion> - <exclusion> - <groupId>org.apache.httpcomponents</groupId> - <artifactId>fluent-hc</artifactId> - </exclusion> - <exclusion> - <groupId>org.apache.httpcomponents</groupId> - <artifactId>httpcore</artifactId> - </exclusion> - <exclusion> - <groupId>org.apache.httpcomponents</groupId> - <artifactId>httpclient</artifactId> - </exclusion> <exclusion> <groupId>com.thoughtworks.paranamer</groupId> <artifactId>paranamer</artifactId> @@ -327,7 +315,7 @@ <packageName>fr.ird.observe.services.client</packageName> <serviceSupportType>fr.ird.observe.services.client.ObserveServiceClientSupport</serviceSupportType> <gsonType>io.ultreia.java4all.util.json.JsonAware</gsonType> - <addAuthToken>true</addAuthToken> + <addAuthenticationToken>true</addAuthenticationToken> <classSuffix>Client</classSuffix> </configuration> </execution> ===================================== core/services/client/src/main/java/fr/ird/observe/services/client/ObserveRequestBuilder.java ===================================== @@ -24,10 +24,12 @@ package fr.ird.observe.services.client; import fr.ird.observe.datasource.configuration.rest.ObserveDataSourceConfigurationRestConstants; import fr.ird.observe.services.ObserveServiceInitializerConfig; +import io.ultreia.java4all.http.HRequest; import io.ultreia.java4all.http.HRequestBuilder; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.util.Objects; -import java.util.concurrent.TimeUnit; /** * Created by tchemit on 17/07/17. @@ -35,14 +37,13 @@ import java.util.concurrent.TimeUnit; * @author Tony Chemit - dev@tchemit.fr */ public class ObserveRequestBuilder extends HRequestBuilder { + private static final Logger log = LogManager.getLogger(ObserveRequestBuilder.class); ObserveRequestBuilder(ObserveServiceClientContext serviceContext, String baseUrl) { super(serviceContext.getServiceUrl(baseUrl)); ObserveServiceInitializerConfig initializerConfig = serviceContext.getInitializer().getInitializerConfig(); - int defaultTimeout = initializerConfig.getHttpTimeout(); - setTimeout(TimeUnit.MILLISECONDS, defaultTimeout); if (serviceContext.getInitializer().withConnection()) { - addAuthTokenSupplier(serviceContext.getAuthTokenSupplier()); + addAuthenticationTokenSupplier(serviceContext.getAuthTokenSupplier()); } if (initializerConfig.withApplicationLocale()) { addHeader(ObserveDataSourceConfigurationRestConstants.REQUEST_APPLICATION_LOCALE, initializerConfig.getApplicationLocale().toString()); @@ -53,17 +54,16 @@ public class ObserveRequestBuilder extends HRequestBuilder { } @Override - protected void setAuthTokenInRequest() { - String authToken = authTokenSupplier.get(); - Objects.requireNonNull(authToken, "Can't add null authToken"); - addHeader(ObserveDataSourceConfigurationRestConstants.REQUEST_AUTHENTICATION_TOKEN, authToken); + protected void setAuthenticationTokenInRequest() { + String authenticationToken = authenticationTokenSupplier.get(); + Objects.requireNonNull(authenticationToken, "Can't add null authenticationToken"); + addHeader(ObserveDataSourceConfigurationRestConstants.REQUEST_AUTHENTICATION_TOKEN, authenticationToken); } @Override - public HRequestBuilder setTimeout(TimeUnit timeUnit, int timeout) { - super.setTimeout(timeUnit, timeout); - //FIXME See the difference with timeout, but it seems strange to have a lesser value here - super.setSocketTimeout(timeUnit, timeout); - return this; + protected HRequest build() { + HRequest request = super.build(); + log.debug("Created request: {}", request); + return request; } } ===================================== core/services/client/src/main/java/fr/ird/observe/services/client/ObserveServiceFactoryClient.java ===================================== @@ -31,10 +31,17 @@ import fr.ird.observe.services.service.ObserveService; import fr.ird.observe.spi.json.DtoGsonSupplier; import io.ultreia.java4all.http.HResponseBuilder; import io.ultreia.java4all.lang.Strings; +import org.apache.hc.client5.http.config.ConnectionConfig; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.cookie.BasicCookieStore; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; +import org.apache.hc.client5.http.impl.io.BasicHttpClientConnectionManager; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.Objects; +import java.util.concurrent.TimeUnit; /** * Created on 16/08/15. @@ -48,7 +55,30 @@ public class ObserveServiceFactoryClient implements ObserveServiceFactory { private final static ClassMappingClient CLASS_MAPPING = ClassMappingClient.get(); private final static int LOCATE_PREFIX_LENGTH = ObserveServiceClientSupport.class.getPackage().getName().length(); private final ObserveRequestBuilderFactory requestBuilderFactory = new ObserveRequestBuilderFactory(); - private final HResponseBuilder responseBuilder = HResponseBuilder.create(new DtoGsonSupplier()); + + private HResponseBuilder responseBuilder; + + private synchronized HResponseBuilder getResponseBuilder(ObserveServiceInitializer serviceInitializer) { + if (responseBuilder == null) { + int timeout = serviceInitializer.getInitializerConfig().getHttpTimeout(); + ConnectionConfig connConfig = ConnectionConfig.custom() + .setSocketTimeout(timeout, TimeUnit.MILLISECONDS) + .build(); + BasicHttpClientConnectionManager cm = new BasicHttpClientConnectionManager(); + cm.setConnectionConfig(connConfig); + CloseableHttpClient httpClient = HttpClientBuilder.create() + .setConnectionManager(cm) + .setDefaultCookieStore(new BasicCookieStore()) + .setDefaultRequestConfig(RequestConfig.custom().setResponseTimeout(timeout, TimeUnit.MILLISECONDS).build()) + //FIXME-migration +// .setMaxConnTotal(1000) +// .setMaxConnPerRoute(1000) +// .setConnectionTimeToLive(45, TimeUnit.SECONDS) + .build(); + responseBuilder = HResponseBuilder.create(new DtoGsonSupplier(), httpClient); + } + return responseBuilder; + } @Override public <S extends ObserveService> boolean accept(ObserveDataSourceConfiguration dataSourceConfiguration, Class<S> serviceType) { @@ -88,7 +118,7 @@ public class ObserveServiceFactoryClient implements ObserveServiceFactory { serviceLocation = Strings.removeEnd(serviceLocation, "Client"); ObserveServiceClientContext serviceRestApiContext = new ObserveServiceClientContext( serviceInitializer, - responseBuilder, + getResponseBuilder(serviceInitializer), requestBuilderFactory, serviceLocation); ((ObserveServiceClientSupport) service).setServiceContext(serviceRestApiContext); @@ -97,10 +127,12 @@ public class ObserveServiceFactoryClient implements ObserveServiceFactory { @Override public void close() { - try { - responseBuilder.close(); - } catch (Exception e) { - log.error("Can't close response builder", e); + if (responseBuilder != null) { + try { + responseBuilder.close(); + } catch (Exception e) { + log.error("Can't close response builder", e); + } } } ===================================== pom.xml ===================================== @@ -23,7 +23,7 @@ <parent> <groupId>io.ultreia.maven</groupId> <artifactId>pom</artifactId> - <version>2023.47</version> + <version>2023.51</version> </parent> <groupId>fr.ird.observe</groupId> <artifactId>ird-observe</artifactId> @@ -277,6 +277,16 @@ <artifactId>commons-fileupload</artifactId> <version>${lib.version.commons-fileupload}</version> </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-fileupload2-core</artifactId> + <version>${lib.version.commons-fileupload2}</version> + </dependency> + <dependency> + <groupId>org.apache.commons</groupId> + <artifactId>commons-fileupload2-jakarta</artifactId> + <version>${lib.version.commons-fileupload2}</version> + </dependency> <dependency> <groupId>commons-io</groupId> <artifactId>commons-io</artifactId> @@ -550,14 +560,14 @@ <version>${lib.version.commons-text}</version> </dependency> <dependency> - <groupId>org.apache.httpcomponents</groupId> - <artifactId>httpclient</artifactId> - <version>${lib.version.httpclient}</version> + <groupId>org.apache.httpcomponents.client5</groupId> + <artifactId>httpclient5</artifactId> + <version>${lib.version.httpclient5}</version> </dependency> <dependency> - <groupId>org.apache.httpcomponents</groupId> - <artifactId>httpcore</artifactId> - <version>${lib.version.httpcore}</version> + <groupId>org.apache.httpcomponents.core5</groupId> + <artifactId>httpcore5</artifactId> + <version>${lib.version.httpcore5}</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> ===================================== server/configuration/src/main/resources/log4j2.xml ===================================== @@ -64,6 +64,10 @@ <Logger name="org.debux.webmotion.server" level="info" additivity="false"> <AppenderRef ref="console"/> </Logger> + <!-- To See all multi-part loaded --> + <!--<Logger name="org.debux.webmotion.server.handler.ParametersMultipartHandler" level="debug" additivity="false"> + <AppenderRef ref="console"/> + </Logger>--> <Logger name="fr.ird.observe" level="info" additivity="false"> <AppenderRef ref="console"/> </Logger> ===================================== server/core/src/main/filtered-resources/META-INF/mapping-api-client.wm ===================================== @@ -64,7 +64,7 @@ DELETE /api/DataEntityService/delete api. GET /api/DataEntityService/generateId api.DataEntityServiceRestApi.generateId GET /api/DataEntityService/getOne api.DataEntityServiceRestApi.getOne GET /api/DataEntityService/getSome api.DataEntityServiceRestApi.getSome -POST /api/DataEntityService/update api.DataEntityServiceRestApi.update +PUT /api/DataEntityService/update api.DataEntityServiceRestApi.update POST /api/ReferentialEntityService/create api.ReferentialEntityServiceRestApi.create DELETE /api/ReferentialEntityService/delete api.ReferentialEntityServiceRestApi.delete GET /api/ReferentialEntityService/generateId api.ReferentialEntityServiceRestApi.generateId ===================================== server/core/src/main/java/fr/ird/observe/server/ObserveWebApplicationListener.java ===================================== @@ -53,12 +53,15 @@ public class ObserveWebApplicationListener implements WebMotionServerListener { contextPath = contextPath.substring(1); } log.info(String.format("Application starting on [%s] at %s...", contextPath, new Date())); + ObserveWebApplicationContext applicationContext; try { - ObserveWebApplicationContext applicationContext = ObserveWebApplicationContext.init(contextPath); + applicationContext = ObserveWebApplicationContext.init(contextPath); servletContext.setAttribute(ObserveWebApplicationContext.APPLICATION_CONTEXT_PARAMETER, applicationContext); } catch (Exception e) { throw new ObserveWebApplicationContextInitException("Can't init application context", e); } + context.setTemporaryPath(applicationContext.getApplicationConfiguration().getTemporaryDirectory().toPath()); + log.info(String.format("Initializing %s done.", this)); } ===================================== server/core/src/main/java/fr/ird/observe/server/request/ObserveWebRequestContext.java ===================================== @@ -141,7 +141,7 @@ public class ObserveWebRequestContext { public void checkAuthentication(ObserveWebUserSession session, Class<? extends ObserveService> serviceType, Method method) { Method serviceMethod = getServiceMethod(serviceType, method); RequestAnnotation requestAnnotation = SpiHelper.getRequestAnnotation(serviceMethod); - boolean requiredAuthentication = requestAnnotation.isAddAuthToken(); + boolean requiredAuthentication = requestAnnotation.isAddAuthenticationToken(); boolean withConnection = session.withConnection(); if (requiredAuthentication) { if (!withConnection) { ===================================== server/runner/src/main/resources/META-INF/configuration/log.xml ===================================== @@ -106,6 +106,11 @@ <AppenderRef ref="console"/> <AppenderRef ref="File"/> </Logger> + <!-- To See all multi-part loaded --> + <!--<Logger name="org.debux.webmotion.server.handler.ParametersMultipartHandler" level="debug" additivity="false"> + <AppenderRef ref="console"/> + <AppenderRef ref="File"/> + </Logger>--> <Root level="error"> <AppenderRef ref="console"/> <AppenderRef ref="File"/> ===================================== toolkit/api-services/src/main/java/fr/ird/observe/services/service/AnonymousService.java ===================================== @@ -49,45 +49,45 @@ import java.util.Set; @Service public interface AnonymousService extends ObserveService { - @Get(addAuthtoken = false) + @Get(addAuthenticationToken = false) Version getModelVersion(); - @Get(addAuthtoken = false) + @Get(addAuthenticationToken = false) Version getServerVersion(); - @Get(addAuthtoken = false) + @Get(addAuthenticationToken = false) ObserveDataSourceInformation checkCanConnect(ObserveDataSourceConfiguration config) throws DatabaseNotFoundException, DatabaseConnexionNotAuthorizedException, BabModelVersionException; - @Get(addAuthtoken = false) + @Get(addAuthenticationToken = false) ObserveDataSourceInformation checkCanConnectOrBeEmpty(ObserveDataSourceConfiguration config) throws DatabaseNotFoundException, DatabaseConnexionNotAuthorizedException, BabModelVersionException; - @Post(addAuthtoken = false) + @Post(addAuthenticationToken = false) ObserveDataSourceConnection createEmpty(ObserveDataSourceConfiguration config) throws IncompatibleDataSourceCreateConfigurationException, DataSourceCreateWithNoReferentialImportException, BabModelVersionException, DatabaseConnexionNotAuthorizedException, DatabaseNotFoundException; - @Post(addAuthtoken = false, useMultiPartForm = true) + @Post(addAuthenticationToken = false, useMultiPartForm = true) ObserveDataSourceConnection createFromDump(ObserveDataSourceConfiguration config, SqlScript dump) throws IncompatibleDataSourceCreateConfigurationException, DataSourceCreateWithNoReferentialImportException, BabModelVersionException, DatabaseConnexionNotAuthorizedException, DatabaseNotFoundException; - @Post(addAuthtoken = false, useMultiPartForm = true) + @Post(addAuthenticationToken = false, useMultiPartForm = true) ObserveDataSourceConnection createFromImport(ObserveDataSourceConfiguration config, SqlScript dump, @Nullable SqlScript optionalDump) throws IncompatibleDataSourceCreateConfigurationException, DataSourceCreateWithNoReferentialImportException, BabModelVersionException, DatabaseConnexionNotAuthorizedException, DatabaseNotFoundException; - @Get(addAuthtoken = false) + @Get(addAuthenticationToken = false) ObserveDataSourceConnection open(ObserveDataSourceConfiguration config) throws DatabaseNotFoundException, DatabaseConnexionNotAuthorizedException, BabModelVersionException; - @Get(addAuthtoken = false) + @Get(addAuthenticationToken = false) Set<DataSourceUserDto> getUsers(ObserveDataSourceConfiguration config); - @Get(addAuthtoken = false, timeOut = 100) + @Get(addAuthenticationToken = false, timeOut = 100) void applySecurity(ObserveDataSourceConfiguration config, Set<DataSourceUserDto> users); - @Get(addAuthtoken = false, timeOut = 100) + @Get(addAuthenticationToken = false, timeOut = 100) void migrateData(ObserveDataSourceConfiguration config); - @Get(addAuthtoken = false) + @Get(addAuthenticationToken = false) String generateHomeId(); /** * @return list of available databases (only available for server service) */ - @Get(addAuthtoken = false) + @Get(addAuthenticationToken = false) Set<String> getAvailableDatabaseNames(); } ===================================== toolkit/api-services/src/main/java/fr/ird/observe/services/service/UsageService.java ===================================== @@ -26,6 +26,7 @@ import fr.ird.observe.datasource.security.Permission; import fr.ird.observe.dto.BusinessDto; import fr.ird.observe.dto.ToolkitIdDtoBean; import fr.ird.observe.dto.ToolkitIdLabel; +import io.ultreia.java4all.http.spi.Get; import io.ultreia.java4all.http.spi.Post; import io.ultreia.java4all.http.spi.Service; @@ -40,9 +41,11 @@ import java.util.Set; @Service public interface UsageService extends ObserveService { + @Get @MethodCredential(Permission.READ_ALL) UsageCount countReferential(ToolkitIdDtoBean request); + @Get @MethodCredential(Permission.READ_ALL) UsageCount countReferentialInData(ToolkitIdDtoBean request); @@ -50,9 +53,11 @@ public interface UsageService extends ObserveService { @MethodCredential(Permission.READ_REFERENTIAL) <D extends BusinessDto> Set<ToolkitIdLabel> findReferential(ToolkitIdDtoBean request, Class<D> targetType); + @Get @MethodCredential(Permission.READ_DATA) UsageCount countOptionalData(ToolkitIdDtoBean request); + @Get @MethodCredential(Permission.READ_DATA) UsageCount countMandatoryData(ToolkitIdDtoBean request); ===================================== toolkit/api-services/src/main/java/fr/ird/observe/services/service/api/DataEntityService.java ===================================== @@ -33,6 +33,7 @@ import io.ultreia.java4all.http.spi.Delete; import io.ultreia.java4all.http.spi.Get; import io.ultreia.java4all.http.spi.Nullable; import io.ultreia.java4all.http.spi.Post; +import io.ultreia.java4all.http.spi.Put; import io.ultreia.java4all.http.spi.Service; import io.ultreia.java4all.http.spi.Write; @@ -62,7 +63,7 @@ public interface DataEntityService extends ObserveService { return getSome(dtoType, config, filters, Map.of()); } - @Get(addAuthtoken = false) + @Get(addAuthenticationToken = false) List<String> generateId(Class<? extends DataDto> dtoType, int number); @Post(useMultiPartForm = true) @@ -70,7 +71,7 @@ public interface DataEntityService extends ObserveService { @Write ToolkitId create(Class<? extends DataDto> dtoType, String content) throws InvalidDataException; - @Post(useMultiPartForm = true) + @Put(useMultiPartForm = true) @MethodCredential(Permission.READ_ALL_AND_WRITE_DATA) @Write ToolkitId update(Class<? extends DataDto> dtoType, String id, String content) throws InvalidDataException; ===================================== toolkit/api-services/src/main/java/fr/ird/observe/services/service/api/ReferentialEntityService.java ===================================== @@ -81,7 +81,7 @@ public interface ReferentialEntityService extends ObserveService { return getSome(dtoType, config, filters, Map.of()); } - @Get(addAuthtoken = false) + @Get(addAuthenticationToken = false) List<String> generateId(Class<? extends ReferentialDto> dtoType, int number); @Post(useMultiPartForm = true) ===================================== toolkit/plugin/src/main/java/fr/ird/observe/toolkit/maven/plugin/service/ServiceGenerateApiRunner.java ===================================== @@ -35,11 +35,8 @@ import fr.ird.observe.spi.navigation.model.tree.TreeProjectModelBuilder; import fr.ird.observe.toolkit.maven.plugin.MojoRunnable; import io.ultreia.java4all.http.spi.Delete; import io.ultreia.java4all.http.spi.Get; -import io.ultreia.java4all.http.spi.Head; -import io.ultreia.java4all.http.spi.Patch; import io.ultreia.java4all.http.spi.Post; import io.ultreia.java4all.http.spi.Put; -import io.ultreia.java4all.http.spi.Trace; import io.ultreia.java4all.http.spi.Write; import io.ultreia.java4all.http.spi.model.ImportManager; import io.ultreia.java4all.http.spi.model.MethodDescription; @@ -227,6 +224,20 @@ public class ServiceGenerateApiRunner extends MojoRunnable { } + private String addMethodAnnotation(boolean addAuthenticationToken, boolean useMultiPartForm, int timeOut) { + String parameters = ""; + if (!addAuthenticationToken) { + parameters += ", addAuthenticationToken = false"; + } + if (useMultiPartForm) { + parameters += ", useMultiPartForm = true"; + } + if (timeOut != 0) { + parameters += ", timeOut = " + timeOut; + } + return parameters; + } + protected void addMethod(ServiceLocalMethodDescriptionImpl methodDescription, List<String> methods) { Permission methodeCredentials = methodDescription.getMethodeCredentials(); StringBuilder annotationsBuilder = new StringBuilder(); @@ -243,104 +254,32 @@ public class ServiceGenerateApiRunner extends MojoRunnable { parameters += ", " + Permission.class.getSimpleName() + "." + methodeCredentials.name(); } else if (annotation instanceof Get) { Get annotation1 = (Get) annotation; - boolean addAuthToken = annotation1.addAuthtoken(); - boolean useMultiPartForm = annotation1.useMultiPartForm(); + boolean addAuthenticationToken = annotation1.addAuthenticationToken(); + boolean useMultiPartForm = false; int timeOut = annotation1.timeOut(); - if (!addAuthToken) { - parameters += ", addAuthtoken = false"; - } - if (useMultiPartForm) { - parameters += ", useMultiPartForm = true"; - } - if (timeOut != 1) { - parameters += ", timeOut = " + timeOut; - } + parameters += addMethodAnnotation(addAuthenticationToken, useMultiPartForm, timeOut); } else if (annotation instanceof Post) { Post annotation1 = (Post) annotation; - boolean addAuthToken = annotation1.addAuthtoken(); + boolean addAuthenticationToken = annotation1.addAuthenticationToken(); boolean useMultiPartForm = annotation1.useMultiPartForm(); int timeOut = annotation1.timeOut(); - if (!addAuthToken) { - parameters += ", addAuthtoken = false"; - } - if (useMultiPartForm) { - parameters += ", useMultiPartForm = true"; - } - if (timeOut != 1) { - parameters += ", timeOut = " + timeOut; - } + parameters += addMethodAnnotation(addAuthenticationToken, useMultiPartForm, timeOut); + } else if (annotation instanceof Put) { Put annotation1 = (Put) annotation; - boolean addAuthToken = annotation1.addAuthtoken(); + boolean addAuthenticationToken = annotation1.addAuthenticationToken(); boolean useMultiPartForm = annotation1.useMultiPartForm(); int timeOut = annotation1.timeOut(); - if (!addAuthToken) { - parameters += ", addAuthtoken = false"; - } - if (useMultiPartForm) { - parameters += ", useMultiPartForm = true"; - } - if (timeOut != 1) { - parameters += ", timeOut = " + timeOut; - } + parameters += addMethodAnnotation(addAuthenticationToken, useMultiPartForm, timeOut); + } else if (annotation instanceof Delete) { Delete annotation1 = (Delete) annotation; - boolean addAuthToken = annotation1.addAuthtoken(); + boolean addAuthenticationToken = annotation1.addAuthenticationToken(); boolean useMultiPartForm = annotation1.useMultiPartForm(); int timeOut = annotation1.timeOut(); - if (!addAuthToken) { - parameters += ", addAuthtoken = false"; - } - if (useMultiPartForm) { - parameters += ", useMultiPartForm = true"; - } - if (timeOut != 1) { - parameters += ", timeOut = " + timeOut; - } - } else if (annotation instanceof Patch) { - Patch annotation1 = (Patch) annotation; - boolean addAuthToken = annotation1.addAuthtoken(); - boolean useMultiPartForm = annotation1.useMultiPartForm(); - int timeOut = annotation1.timeOut(); - if (!addAuthToken) { - parameters += ", addAuthtoken = false"; - } - if (useMultiPartForm) { - parameters += ", useMultiPartForm = true"; - } - if (timeOut != 1) { - parameters += ", timeOut = " + timeOut; - } - } else if (annotation instanceof Head) { - Head annotation1 = (Head) annotation; - boolean addAuthToken = annotation1.addAuthtoken(); - boolean useMultiPartForm = annotation1.useMultiPartForm(); - int timeOut = annotation1.timeOut(); - if (!addAuthToken) { - parameters += ", addAuthtoken = false"; - } - if (useMultiPartForm) { - parameters += ", useMultiPartForm = true"; - } - if (timeOut != 1) { - parameters += ", timeOut = " + timeOut; - } - } else if (annotation instanceof Trace) { - Trace annotation1 = (Trace) annotation; - boolean addAuthToken = annotation1.addAuthtoken(); - boolean useMultiPartForm = annotation1.useMultiPartForm(); - int timeOut = annotation1.timeOut(); - if (!addAuthToken) { - parameters += ", addAuthtoken = false"; - } - if (useMultiPartForm) { - parameters += ", useMultiPartForm = true"; - } - if (timeOut != 1) { - parameters += ", timeOut = " + timeOut; - } + parameters += addMethodAnnotation(addAuthenticationToken, useMultiPartForm, timeOut); } - if (parameters.length() > 0) { + if (!parameters.isEmpty()) { annotationsBuilder.append("(").append(parameters.substring(2)).append(")"); } } ===================================== toolkit/plugin/src/main/java/fr/ird/observe/toolkit/maven/plugin/service/ServiceLocalMethodDescriptionImpl.java ===================================== @@ -75,7 +75,7 @@ public class ServiceLocalMethodDescriptionImpl implements MethodDescription { this.methodeCredentials = Optional.ofNullable(method.getAnnotation(MethodCredential.class)).map(MethodCredential::value).orElse(null); this.write = SpiHelper.write(method); - this.noTransaction = !SpiHelper.getRequestAnnotation(method).isAddAuthToken(); + this.noTransaction = !SpiHelper.getRequestAnnotation(method).isAddAuthenticationToken(); } public Method getMethod() { ===================================== toolkit/server/pom.xml ===================================== @@ -42,8 +42,8 @@ <artifactId>commons-configuration</artifactId> </dependency> <dependency> - <groupId>commons-fileupload</groupId> - <artifactId>commons-fileupload</artifactId> + <groupId>org.apache.commons</groupId> + <artifactId>commons-fileupload2-core</artifactId> </dependency> <dependency> <groupId>commons-io</groupId> @@ -65,14 +65,6 @@ <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> </dependency> - <dependency> - <groupId>org.apache.httpcomponents</groupId> - <artifactId>httpclient</artifactId> - </dependency> - <dependency> - <groupId>org.apache.httpcomponents</groupId> - <artifactId>httpcore</artifactId> - </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> ===================================== toolkit/server/src/main/java/org/debux/webmotion/server/call/ServerContext.java ===================================== @@ -25,6 +25,7 @@ import io.ultreia.java4all.lang.Objects2; import org.apache.commons.beanutils.BeanUtilsBean; import org.apache.commons.beanutils.ConvertUtilsBean; import org.apache.commons.beanutils.Converter; +import org.apache.commons.fileupload2.core.DiskFileItemFactory; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.debux.webmotion.server.WebMotionController; @@ -44,6 +45,7 @@ import org.debux.webmotion.server.tools.SingletonFactory; import javax.servlet.ServletContext; import java.lang.reflect.Method; +import java.nio.file.Path; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -136,6 +138,16 @@ public class ServerContext { * Current exclude paths */ protected String[] excludePaths = {}; + /** + * Temporary path used + */ + protected Path temporaryPath; + /** + * Use to read multi-parts. + * + * @see org.debux.webmotion.server.handler.ParametersMultipartHandler + */ + protected DiskFileItemFactory fileItemFactory; /** * Initialize the context. @@ -461,6 +473,24 @@ public class ServerContext { this.excludePaths = excludePaths; } + public Path getTemporaryPath() { + return temporaryPath; + } + + public void setTemporaryPath(Path temporaryPath) { + this.temporaryPath = temporaryPath; + } + + public synchronized DiskFileItemFactory getFileItemFactory() { + if (fileItemFactory == null) { + if (getTemporaryPath() == null) { + throw new IllegalStateException("No temporary path set in the ServerContext."); + } + fileItemFactory = DiskFileItemFactory.builder().setBufferSize(1024 * 1024 /* 1Mb */).setPath(getTemporaryPath()).get(); + } + return fileItemFactory; + } + private static final Logger log = LogManager.getLogger(ServerContext.class); public void loadExecutors(Mapping mapping, Stream<? extends Rule> actionStream) { ===================================== toolkit/server/src/main/java/org/debux/webmotion/server/handler/ExecutorMethodInvokerHandler.java ===================================== @@ -30,7 +30,7 @@ import org.debux.webmotion.server.WebMotionFilter; import org.debux.webmotion.server.WebMotionHandler; import org.debux.webmotion.server.call.Call; import org.debux.webmotion.server.call.Executor; -import org.debux.webmotion.server.call.FileProgressListener; +import org.debux.webmotion.server.tools.upload.FileProgressListener; import org.debux.webmotion.server.call.HttpContext; import org.debux.webmotion.server.call.ServerContext; import org.debux.webmotion.server.mapping.Action; ===================================== toolkit/server/src/main/java/org/debux/webmotion/server/handler/ExecutorParametersInjectorHandler.java ===================================== @@ -24,7 +24,7 @@ package org.debux.webmotion.server.handler; import org.debux.webmotion.server.WebMotionHandler; import org.debux.webmotion.server.call.Call; import org.debux.webmotion.server.call.Executor; -import org.debux.webmotion.server.call.FileProgressListener; +import org.debux.webmotion.server.tools.upload.FileProgressListener; import org.debux.webmotion.server.call.HttpContext; import org.debux.webmotion.server.call.HttpContext.ErrorData; import org.debux.webmotion.server.call.ServerContext; ===================================== toolkit/server/src/main/java/org/debux/webmotion/server/handler/ParametersMultipartHandler.java ===================================== @@ -21,25 +21,24 @@ */ package org.debux.webmotion.server.handler; -import org.apache.commons.fileupload.FileItem; -import org.apache.commons.fileupload.FileItemFactory; -import org.apache.commons.fileupload.FileUploadException; -import org.apache.commons.fileupload.disk.DiskFileItem; -import org.apache.commons.fileupload.disk.DiskFileItemFactory; -import org.apache.commons.fileupload.servlet.ServletFileUpload; +import io.ultreia.java4all.lang.Strings; +import org.apache.commons.fileupload2.core.DiskFileItem; import org.apache.commons.lang3.ArrayUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import org.debux.webmotion.server.WebMotionException; import org.debux.webmotion.server.WebMotionHandler; import org.debux.webmotion.server.call.Call; -import org.debux.webmotion.server.call.FileProgressListener; import org.debux.webmotion.server.call.HttpContext; import org.debux.webmotion.server.call.UploadFile; import org.debux.webmotion.server.mapping.Mapping; +import org.debux.webmotion.server.tools.upload.FileUpload; import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpSession; import java.io.File; +import java.io.IOException; import java.io.UnsupportedEncodingException; +import java.nio.charset.StandardCharsets; import java.util.List; import java.util.Map; @@ -51,6 +50,8 @@ import java.util.Map; */ public class ParametersMultipartHandler extends AbstractHandler implements WebMotionHandler { + private static final Logger log = LogManager.getLogger(ParametersMultipartHandler.class); + @Override public void handle(Mapping mapping, Call call) { HttpContext context = call.getContext(); @@ -58,29 +59,28 @@ public class ParametersMultipartHandler extends AbstractHandler implements WebMo Map<String, Object> extractParameters = call.getExtractParameters(); - boolean isMultipart = ServletFileUpload.isMultipartContent(request); + boolean isMultipart = FileUpload.isMultipartContent(request); if (isMultipart) { - FileItemFactory fileItemFactory = new DiskFileItemFactory(0, null); - ServletFileUpload upload = new ServletFileUpload(fileItemFactory); - - HttpSession session = request.getSession(); - if (session != null) { - FileProgressListener listener = new FileProgressListener(); - upload.setProgressListener(listener); - session.setAttribute(FileProgressListener.SESSION_ATTRIBUTE_NAME, listener); - call.setFileUploadRequest(true); - } + FileUpload upload = new FileUpload(context.getServerContext().getFileItemFactory()); + +// HttpSession session = request.getSession(); +// if (session != null) { +// FileProgressListener listener = new FileProgressListener(); +// upload.setProgressListener(listener); +// session.setAttribute(FileProgressListener.SESSION_ATTRIBUTE_NAME, listener); +// call.setFileUploadRequest(true); +// } try { - List<FileItem> items = upload.parseRequest(request); - for (FileItem item0 : items) { - DiskFileItem item = (DiskFileItem) item0; + List<DiskFileItem> items = upload.parseRequest(request); + for (DiskFileItem item : items) { String fieldName = item.getFieldName(); + log.debug("Multipart: {} - size: {} - in memory? {} - location: {}", fieldName, Strings.convertMemory(item.getSize()), item.isInMemory(), item.getPath()); if (item.isFormField()) { String fieldValue; try { - fieldValue = item.getString("UTF-8"); + fieldValue = item.getString(StandardCharsets.UTF_8); } catch (UnsupportedEncodingException e) { fieldValue = item.getString(); } @@ -96,24 +96,12 @@ public class ParametersMultipartHandler extends AbstractHandler implements WebMo } } else { - UploadFile uploadFile = new UploadFile(); - - File file = item.getStoreLocation(); - uploadFile.setFile(file); - - String fileName = item.getName(); - uploadFile.setName(fileName); - - long fileSize = item.getSize(); - uploadFile.setSize(fileSize); - - String fileType = item.getContentType(); - uploadFile.setContentType(fileType); + UploadFile uploadFile = getUploadFile(item); extractParameters.put(fieldName, uploadFile); } } - } catch (FileUploadException fue) { + } catch (IOException fue) { throw new WebMotionException("Error during upload file on server", fue); } @@ -122,4 +110,21 @@ public class ParametersMultipartHandler extends AbstractHandler implements WebMo extractParameters.putAll(parameters); } } + + private static UploadFile getUploadFile(DiskFileItem item) { + UploadFile uploadFile = new UploadFile(); + + File file = item.getPath().toFile(); + uploadFile.setFile(file); + + String fileName = item.getName(); + uploadFile.setName(fileName); + + long fileSize = item.getSize(); + uploadFile.setSize(fileSize); + + String fileType = item.getContentType(); + uploadFile.setContentType(fileType); + return uploadFile; + } } ===================================== toolkit/server/src/main/java/org/debux/webmotion/server/call/FileProgressListener.java → toolkit/server/src/main/java/org/debux/webmotion/server/tools/upload/FileProgressListener.java ===================================== @@ -19,9 +19,9 @@ * <http://www.gnu.org/licenses/gpl-3.0.html>. * #L% */ -package org.debux.webmotion.server.call; +package org.debux.webmotion.server.tools.upload; -import org.apache.commons.fileupload.ProgressListener; +import org.apache.commons.fileupload2.core.ProgressListener; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -30,7 +30,6 @@ import org.apache.logging.log4j.Logger; * stored in session. * * @author julien - * @see org.apache.commons.fileupload.FileUpload */ public class FileProgressListener implements ProgressListener { ===================================== toolkit/server/src/main/java/org/debux/webmotion/server/tools/upload/FileUpload.java ===================================== @@ -0,0 +1,69 @@ +package org.debux.webmotion.server.tools.upload; + +/*- + * #%L + * ObServe Toolkit :: Server + * %% + * Copyright (C) 2008 - 2023 IRD, Ultreia.io + * %% + * 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.apache.commons.fileupload2.core.AbstractFileUpload; +import org.apache.commons.fileupload2.core.DiskFileItem; +import org.apache.commons.fileupload2.core.DiskFileItemFactory; +import org.apache.commons.fileupload2.core.FileItemInputIterator; +import org.apache.commons.fileupload2.core.FileUploadException; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; + +/** + * Created at 24/11/2023. + * + * @author Tony Chemit - dev@tchemit.fr + * @since 9.3.0 + */ +public class FileUpload extends AbstractFileUpload<HttpServletRequest, DiskFileItem, DiskFileItemFactory> { + + public static final Set<String> ACCEPTED_METHOD = Set.of("post","put"); + public FileUpload(DiskFileItemFactory fileItemFactory) { + setFileItemFactory(Objects.requireNonNull(fileItemFactory)); + } + + public static boolean isMultipartContent(final HttpServletRequest request) { + return ACCEPTED_METHOD.contains(request.getMethod().toLowerCase()) && AbstractFileUpload.isMultipartContent(new RequestContext(request)); + } + + @Override + public FileItemInputIterator getItemIterator(HttpServletRequest request) throws IOException { + return super.getItemIterator(new RequestContext(request)); + } + + @Override + public Map<String, List<DiskFileItem>> parseParameterMap(HttpServletRequest request) throws FileUploadException { + return super.parseParameterMap(new RequestContext(request)); + } + + @Override + public List<DiskFileItem> parseRequest(HttpServletRequest request) throws FileUploadException { + return super.parseRequest(new RequestContext(request)); + } +} ===================================== toolkit/server/src/main/java/org/debux/webmotion/server/tools/StringResponseHandler.java → toolkit/server/src/main/java/org/debux/webmotion/server/tools/upload/RequestContext.java ===================================== @@ -1,6 +1,6 @@ -package org.debux.webmotion.server.tools; +package org.debux.webmotion.server.tools.upload; -/* +/*- * #%L * ObServe Toolkit :: Server * %% @@ -22,31 +22,59 @@ package org.debux.webmotion.server.tools; * #L% */ -import java.io.IOException; +import org.apache.commons.fileupload2.core.AbstractRequestContext; -import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.ResponseHandler; -import org.apache.http.util.EntityUtils; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.io.InputStream; /** - * Return the content as String without test on status code. - * You can @see ContentResponseHandler for more information. - * - * @author julien + * Created at 24/11/2023. + * + * @author Tony Chemit - dev@tchemit.fr + * @since 9.3.0 */ -public class StringResponseHandler implements ResponseHandler<String> { +public class RequestContext extends AbstractRequestContext<HttpServletRequest> { + + /** + * The request for which the context is being provided. + */ + private final HttpServletRequest request; + + protected RequestContext(HttpServletRequest request) { + super(request::getHeader, request::getContentLength, request); + this.request = request; + } + + /** + * Gets the character encoding for the request. + * + * @return The character encoding for the request. + */ + @Override + public String getCharacterEncoding() { + return request.getCharacterEncoding(); + } + + /** + * Gets the content type of the request. + * + * @return The content type of the request. + */ + @Override + public String getContentType() { + return request.getContentType(); + } + /** + * Gets the input stream for the request. + * + * @return The input stream for the request. + * @throws java.io.IOException if a problem occurs. + */ @Override - public String handleResponse( - final HttpResponse response) throws ClientProtocolException, IOException { - HttpEntity entity = response.getEntity(); - if (entity != null) { - return EntityUtils.toString(entity); - } else { - return null; - } + public InputStream getInputStream() throws IOException { + return request.getInputStream(); } } ===================================== toolkit/server/src/main/resources/META-INF/web-fragment.xml ===================================== @@ -23,11 +23,7 @@ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd"> <name>webmotion</name> - - <listener> - <listener-class>org.apache.commons.fileupload.servlet.FileCleanerCleanup</listener-class> - </listener> - + <listener> <listener-class>org.debux.webmotion.server.WebMotionServletContextListener</listener-class> </listener> View it on GitLab: https://gitlab.com/ultreiaio/ird-observe/-/compare/576a6a8c62fd4e73af30e47a6... -- View it on GitLab: https://gitlab.com/ultreiaio/ird-observe/-/compare/576a6a8c62fd4e73af30e47a6... You're receiving this email because of your account on gitlab.com.