- [x] Create fineract-core module - used to common cross module classes and interfaces

- [x] Create fineract-investor module for build
- [x] modify tenant liquibase loader to using module based liquibase processing
- [x] sample liquibase into the fineract-investor module
- [x] Move NewCommandSourceHandler and dependencies to the fineract-core
This commit is contained in:
Janos Haber
2023-05-15 16:02:59 +02:00
committed by Arnold Gálovics
parent 037f7f264f
commit 240039f979
44 changed files with 433 additions and 2 deletions
@@ -0,0 +1,50 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.commands.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Specifies the command type for the annotated class.<br>
* <br>
* The entity name (e.g. CLIENT, SAVINGSACCOUNT, LOANPRODUCT) and the action (e.g. CREATE, DELETE) must be given.
*
* @author Markus Geiss
* @version 1.0
* @since 15.06
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface CommandType {
/**
* Returns the name of the entity for this {@link CommandType}.
*/
String entity();
/**
* Return the name of the action for this {@link CommandType}.
*/
String action();
}
@@ -0,0 +1,27 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.commands.handler;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
public interface NewCommandSourceHandler {
CommandProcessingResult processCommand(JsonCommand command);
}
@@ -0,0 +1,663 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.core.api;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.reflect.TypeToken;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.MonthDay;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
import java.util.Arrays;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.apache.fineract.infrastructure.security.domain.BasicPasswordEncodablePlatformUser;
import org.apache.fineract.infrastructure.security.domain.PlatformUser;
import org.apache.fineract.infrastructure.security.service.PlatformPasswordEncoder;
/**
* Immutable representation of a command.
*
* Wraps the provided JSON with convenience functions for extracting parameter values and checking for changes against
* an existing value.
*/
public final class JsonCommand {
private final String jsonCommand;
private final JsonElement parsedCommand;
private final FromJsonHelper fromApiJsonHelper;
private final Long commandId;
private final Long resourceId;
private final Long subresourceId;
private final Long groupId;
private final Long clientId;
private final Long loanId;
private final Long savingsId;
private final String entityName;
private final String transactionId;
private final String url;
private final Long productId;
private final Long creditBureauId;
private final Long organisationCreditBureauId;
private final String jobName;
public static JsonCommand from(final String jsonCommand, final JsonElement parsedCommand, final FromJsonHelper fromApiJsonHelper,
final String entityName, final Long resourceId, final Long subresourceId, final Long groupId, final Long clientId,
final Long loanId, final Long savingsId, final String transactionId, final String url, final Long productId,
final Long creditBureauId, final Long organisationCreditBureauId, final String jobName) {
return new JsonCommand(null, jsonCommand, parsedCommand, fromApiJsonHelper, entityName, resourceId, subresourceId, groupId,
clientId, loanId, savingsId, transactionId, url, productId, creditBureauId, organisationCreditBureauId, jobName);
}
public static JsonCommand fromExistingCommand(final Long commandId, final String jsonCommand, final JsonElement parsedCommand,
final FromJsonHelper fromApiJsonHelper, final String entityName, final Long resourceId, final Long subresourceId,
final String url, final Long productId, final Long creditBureauId, final Long organisationCreditBureauId,
final String jobName) {
return new JsonCommand(commandId, jsonCommand, parsedCommand, fromApiJsonHelper, entityName, resourceId, subresourceId, null, null,
null, null, null, url, productId, creditBureauId, organisationCreditBureauId, jobName);
}
public static JsonCommand fromExistingCommand(final Long commandId, final String jsonCommand, final JsonElement parsedCommand,
final FromJsonHelper fromApiJsonHelper, final String entityName, final Long resourceId, final Long subresourceId,
final Long groupId, final Long clientId, final Long loanId, final Long savingsId, final String transactionId, final String url,
final Long productId, Long creditBureauId, final Long organisationCreditBureauId, final String jobName) {
return new JsonCommand(commandId, jsonCommand, parsedCommand, fromApiJsonHelper, entityName, resourceId, subresourceId, groupId,
clientId, loanId, savingsId, transactionId, url, productId, creditBureauId, organisationCreditBureauId, jobName);
}
public static JsonCommand fromExistingCommand(JsonCommand command, final JsonElement parsedCommand) {
final String jsonCommand = command.fromApiJsonHelper.toJson(parsedCommand);
return new JsonCommand(command.commandId, jsonCommand, parsedCommand, command.fromApiJsonHelper, command.entityName,
command.resourceId, command.subresourceId, command.groupId, command.clientId, command.loanId, command.savingsId,
command.transactionId, command.url, command.productId, command.creditBureauId, command.organisationCreditBureauId,
command.jobName);
}
public static JsonCommand fromExistingCommand(JsonCommand command, final JsonElement parsedCommand, final Long clientId) {
final String jsonCommand = command.fromApiJsonHelper.toJson(parsedCommand);
return new JsonCommand(command.commandId, jsonCommand, parsedCommand, command.fromApiJsonHelper, command.entityName,
command.resourceId, command.subresourceId, command.groupId, clientId, command.loanId, command.savingsId,
command.transactionId, command.url, command.productId, command.creditBureauId, command.organisationCreditBureauId,
command.jobName);
}
public JsonCommand(final Long commandId, final String jsonCommand, final JsonElement parsedCommand,
final FromJsonHelper fromApiJsonHelper, final String entityName, final Long resourceId, final Long subresourceId,
final Long groupId, final Long clientId, final Long loanId, final Long savingsId, final String transactionId, final String url,
final Long productId, final Long creditBureauId, final Long organisationCreditBureauId, final String jobName) {
this.commandId = commandId;
this.jsonCommand = jsonCommand;
this.parsedCommand = parsedCommand;
this.fromApiJsonHelper = fromApiJsonHelper;
this.entityName = entityName;
this.resourceId = resourceId;
this.subresourceId = subresourceId;
this.groupId = groupId;
this.clientId = clientId;
this.loanId = loanId;
this.savingsId = savingsId;
this.transactionId = transactionId;
this.url = url;
this.productId = productId;
this.creditBureauId = creditBureauId;
this.organisationCreditBureauId = organisationCreditBureauId;
this.jobName = jobName;
}
public static JsonCommand fromJsonElement(final Long resourceId, final JsonElement parsedCommand) {
return new JsonCommand(resourceId, parsedCommand);
}
public static JsonCommand fromJsonElement(final Long resourceId, final JsonElement parsedCommand,
final FromJsonHelper fromApiJsonHelper) {
return new JsonCommand(resourceId, parsedCommand, fromApiJsonHelper);
}
public JsonCommand(final Long resourceId, final JsonElement parsedCommand) {
this.parsedCommand = parsedCommand;
this.resourceId = resourceId;
this.commandId = null;
this.jsonCommand = null;
this.fromApiJsonHelper = null;
this.entityName = null;
this.subresourceId = null;
this.groupId = null;
this.clientId = null;
this.loanId = null;
this.savingsId = null;
this.transactionId = null;
this.url = null;
this.productId = null;
this.creditBureauId = null;
this.organisationCreditBureauId = null;
this.jobName = null;
}
public JsonCommand(final Long resourceId, final JsonElement parsedCommand, final FromJsonHelper fromApiJsonHelper) {
this.parsedCommand = parsedCommand;
this.resourceId = resourceId;
this.commandId = null;
this.jsonCommand = null;
this.fromApiJsonHelper = fromApiJsonHelper;
this.entityName = null;
this.subresourceId = null;
this.groupId = null;
this.clientId = null;
this.loanId = null;
this.savingsId = null;
this.transactionId = null;
this.url = null;
this.productId = null;
this.creditBureauId = null;
this.organisationCreditBureauId = null;
this.jobName = null;
}
public static JsonCommand from(final String jsonCommand) {
return new JsonCommand(null, jsonCommand, null, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
}
public Long getOrganisationCreditBureauId() {
return this.organisationCreditBureauId;
}
public Long getCreditBureauId() {
return this.creditBureauId;
}
public String json() {
return this.jsonCommand;
}
public JsonElement parsedJson() {
return this.parsedCommand;
}
public JsonElement jsonElement(final String paramName) {
if (this.parsedCommand.getAsJsonObject().has(paramName)) {
return this.parsedCommand.getAsJsonObject().get(paramName);
}
return null;
}
public String jsonFragment(final String paramName) {
String jsonFragment = null;
if (this.parsedCommand.getAsJsonObject().has(paramName)) {
final JsonElement fragment = this.parsedCommand.getAsJsonObject().get(paramName);
jsonFragment = this.fromApiJsonHelper.toJson(fragment);
}
return jsonFragment;
}
public Long commandId() {
return this.commandId;
}
public String entityName() {
return this.entityName;
}
public Long entityId() {
return this.resourceId;
}
public Long subentityId() {
return this.subresourceId;
}
public Long getGroupId() {
return this.groupId;
}
public Long getClientId() {
return this.clientId;
}
public Long getLoanId() {
return this.loanId;
}
public Long getSavingsId() {
return this.savingsId;
}
public String getTransactionId() {
return this.transactionId;
}
public String getUrl() {
return this.url;
}
public Long getProductId() {
return this.productId;
}
public String getJobName() {
return this.jobName;
}
private boolean differenceExists(final TemporalAccessor baseValue, final TemporalAccessor workingCopyValue) {
boolean differenceExists = false;
if (baseValue != null) {
differenceExists = !baseValue.equals(workingCopyValue);
} else {
differenceExists = workingCopyValue != null;
}
return differenceExists;
}
private boolean differenceExists(final String baseValue, final String workingCopyValue) {
boolean differenceExists = false;
if (StringUtils.isNotBlank(baseValue)) {
differenceExists = !baseValue.equals(workingCopyValue);
} else {
differenceExists = StringUtils.isNotBlank(workingCopyValue);
}
return differenceExists;
}
private boolean differenceExists(final String[] baseValue, final String[] workingCopyValue) {
Arrays.sort(baseValue);
Arrays.sort(workingCopyValue);
return !Arrays.equals(baseValue, workingCopyValue);
}
private boolean differenceExists(final Number baseValue, final Number workingCopyValue) {
boolean differenceExists = false;
if (baseValue != null) {
if (workingCopyValue != null) {
differenceExists = !baseValue.equals(workingCopyValue);
} else {
differenceExists = true;
}
} else {
differenceExists = workingCopyValue != null;
}
return differenceExists;
}
private boolean differenceExists(final BigDecimal baseValue, final BigDecimal workingCopyValue) {
boolean differenceExists = false;
if (baseValue != null) {
if (workingCopyValue != null) {
differenceExists = baseValue.compareTo(workingCopyValue) != 0;
} else {
differenceExists = true;
}
} else {
differenceExists = workingCopyValue != null;
}
return differenceExists;
}
private boolean differenceExists(final Boolean baseValue, final Boolean workingCopyValue) {
boolean differenceExists = false;
if (baseValue != null) {
differenceExists = !baseValue.equals(workingCopyValue);
} else {
differenceExists = workingCopyValue != null;
}
return differenceExists;
}
public boolean parameterExists(final String parameterName) {
return this.fromApiJsonHelper.parameterExists(parameterName, this.parsedCommand);
}
public boolean hasParameter(final String parameterName) {
return parameterExists(parameterName);
}
public String dateFormat() {
return stringValueOfParameterNamed("dateFormat");
}
public String locale() {
return stringValueOfParameterNamed("locale");
}
public boolean isChangeInLongParameterNamed(final String parameterName, final Long existingValue) {
boolean isChanged = false;
if (parameterExists(parameterName)) {
final Long workingValue = longValueOfParameterNamed(parameterName);
isChanged = differenceExists(existingValue, workingValue);
}
return isChanged;
}
public Long longValueOfParameterNamed(final String parameterName) {
return this.fromApiJsonHelper.extractLongNamed(parameterName, this.parsedCommand);
}
public boolean isChangeInDateParameterNamed(final String parameterName, final LocalDate existingValue) {
return isChangeInLocalDateParameterNamed(parameterName, existingValue);
}
public boolean isChangeInTimeParameterNamed(final String parameterName, final LocalTime existingValue, final String timeFormat) {
LocalTime time = null;
if (existingValue != null) {
DateTimeFormatter timeFormtter = DateTimeFormatter.ofPattern(timeFormat);
time = LocalTime.parse(existingValue.toString(), timeFormtter);
}
return isChangeInLocalTimeParameterNamed(parameterName, time);
}
public boolean isChangeInLocalTimeParameterNamed(final String parameterName, final LocalTime existingValue) {
boolean isChanged = false;
if (parameterExists(parameterName)) {
final LocalTime workingValue = localTimeValueOfParameterNamed(parameterName);
isChanged = differenceExists(existingValue, workingValue);
}
return isChanged;
}
public boolean isChangeInLocalDateTimeParameterNamed(final String parameterName, final LocalDateTime existingValue) {
boolean isChanged = false;
if (parameterExists(parameterName)) {
final LocalTime workingValue = localTimeValueOfParameterNamed(parameterName);
isChanged = differenceExists(existingValue, workingValue);
}
return isChanged;
}
public boolean isChangeInLocalDateParameterNamed(final String parameterName, final LocalDate existingValue) {
boolean isChanged = false;
if (parameterExists(parameterName)) {
final LocalDate workingValue = localDateValueOfParameterNamed(parameterName);
isChanged = differenceExists(existingValue, workingValue);
}
return isChanged;
}
public LocalDate localDateValueOfParameterNamed(final String parameterName) {
return this.fromApiJsonHelper.extractLocalDateNamed(parameterName, this.parsedCommand);
}
public LocalTime localTimeValueOfParameterNamed(final String parameterName) {
return this.fromApiJsonHelper.extractLocalTimeNamed(parameterName, this.parsedCommand);
}
public LocalDateTime localDateTimeValueOfParameterNamed(final String parameterName) {
return this.fromApiJsonHelper.extractLocalDateTimeNamed(parameterName, this.parsedCommand);
}
public MonthDay extractMonthDayNamed(final String parameterName) {
return this.fromApiJsonHelper.extractMonthDayNamed(parameterName, this.parsedCommand);
}
public LocalDate dateValueOfParameterNamed(final String parameterName) {
return this.fromApiJsonHelper.extractLocalDateNamed(parameterName, this.parsedCommand);
}
public boolean isChangeInStringParameterNamed(final String parameterName, final String existingValue) {
boolean isChanged = false;
if (parameterExists(parameterName)) {
final String workingValue = stringValueOfParameterNamed(parameterName);
isChanged = differenceExists(existingValue, workingValue);
}
return isChanged;
}
public String stringValueOfParameterNamed(final String parameterName) {
final String value = this.fromApiJsonHelper.extractStringNamed(parameterName, this.parsedCommand);
return StringUtils.defaultIfEmpty(value, "");
}
public String stringValueOfParameterNamedAllowingNull(final String parameterName) {
return this.fromApiJsonHelper.extractStringNamed(parameterName, this.parsedCommand);
}
public Map<String, String> mapValueOfParameterNamed(final String json) {
final Type typeOfMap = new TypeToken<Map<String, String>>() {}.getType();
final Map<String, String> value = this.fromApiJsonHelper.extractDataMap(typeOfMap, json);
return value;
}
public Map<String, Object> mapObjectValueOfParameterNamed(final String json) {
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
final Map<String, Object> value = this.fromApiJsonHelper.extractObjectMap(typeOfMap, json);
return value;
}
public boolean isChangeInBigDecimalParameterNamedDefaultingZeroToNull(final String parameterName, final BigDecimal existingValue) {
boolean isChanged = false;
if (parameterExists(parameterName)) {
final BigDecimal workingValue = bigDecimalValueOfParameterNamedDefaultToNullIfZero(parameterName);
isChanged = differenceExists(existingValue, workingValue);
}
return isChanged;
}
public boolean isChangeInBigDecimalParameterNamed(final String parameterName, final BigDecimal existingValue) {
boolean isChanged = false;
if (parameterExists(parameterName)) {
final BigDecimal workingValue = bigDecimalValueOfParameterNamed(parameterName);
isChanged = differenceExists(existingValue, workingValue);
}
return isChanged;
}
public boolean isChangeInBigDecimalParameterNamed(final String parameterName, final BigDecimal existingValue, final Locale locale) {
boolean isChanged = false;
if (parameterExists(parameterName)) {
final BigDecimal workingValue = bigDecimalValueOfParameterNamed(parameterName, locale);
isChanged = differenceExists(existingValue, workingValue);
}
return isChanged;
}
public boolean isChangeInBigDecimalParameterNamedWithNullCheck(final String parameterName, final BigDecimal existingValue) {
boolean isChanged = false;
if (parameterExists(parameterName)) {
final BigDecimal workingValue = bigDecimalValueOfParameterNamed(parameterName);
if (workingValue == null && existingValue != null) {
isChanged = true;
} else {
isChanged = differenceExists(existingValue, workingValue);
}
}
return isChanged;
}
private static BigDecimal defaultToNullIfZero(final BigDecimal value) {
BigDecimal result = value;
if (value != null && BigDecimal.ZERO.compareTo(value) == 0) {
result = null;
}
return result;
}
private static Integer defaultToNullIfZero(final Integer value) {
Integer result = value;
if (value != null && value == 0) {
result = null;
}
return result;
}
public BigDecimal bigDecimalValueOfParameterNamed(final String parameterName) {
return this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed(parameterName, this.parsedCommand);
}
public BigDecimal bigDecimalValueOfParameterNamed(final String parameterName, final Locale locale) {
return this.fromApiJsonHelper.extractBigDecimalNamed(parameterName, this.parsedCommand, locale);
}
public BigDecimal bigDecimalValueOfParameterNamedDefaultToNullIfZero(final String parameterName) {
return defaultToNullIfZero(bigDecimalValueOfParameterNamed(parameterName));
}
public boolean isChangeInIntegerParameterNamedDefaultingZeroToNull(final String parameterName, final Integer existingValue) {
boolean isChanged = false;
if (parameterExists(parameterName)) {
final Integer workingValue = integerValueOfParameterNamedDefaultToNullIfZero(parameterName);
isChanged = differenceExists(existingValue, workingValue);
}
return isChanged;
}
public boolean isChangeInIntegerParameterNamed(final String parameterName, final Integer existingValue) {
boolean isChanged = false;
if (parameterExists(parameterName)) {
final Integer workingValue = integerValueOfParameterNamed(parameterName);
isChanged = differenceExists(existingValue, workingValue);
}
return isChanged;
}
public boolean isChangeInIntegerParameterNamed(final String parameterName, final Integer existingValue, final Locale locale) {
boolean isChanged = false;
if (parameterExists(parameterName)) {
final Integer workingValue = integerValueOfParameterNamed(parameterName, locale);
isChanged = differenceExists(existingValue, workingValue);
}
return isChanged;
}
public boolean isChangeInIntegerParameterNamedWithNullCheck(final String parameterName, final Integer existingValue) {
boolean isChanged = false;
if (parameterExists(parameterName)) {
final Integer workingValue = integerValueOfParameterNamed(parameterName);
if (workingValue == null && existingValue != null) {
isChanged = true;
} else {
isChanged = differenceExists(existingValue, workingValue);
}
}
return isChanged;
}
public Integer integerValueOfParameterNamed(final String parameterName) {
return this.fromApiJsonHelper.extractIntegerWithLocaleNamed(parameterName, this.parsedCommand);
}
public Integer integerValueOfParameterNamed(final String parameterName, final Locale locale) {
return this.fromApiJsonHelper.extractIntegerNamed(parameterName, this.parsedCommand, locale);
}
public Integer integerValueOfParameterNamedDefaultToNullIfZero(final String parameterName) {
return defaultToNullIfZero(integerValueOfParameterNamed(parameterName));
}
public boolean isChangeInIntegerSansLocaleParameterNamed(final String parameterName, final Integer existingValue) {
boolean isChanged = false;
if (parameterExists(parameterName)) {
final Integer workingValue = integerValueSansLocaleOfParameterNamed(parameterName);
isChanged = differenceExists(existingValue, workingValue);
}
return isChanged;
}
public Integer integerValueSansLocaleOfParameterNamed(final String parameterName) {
return this.fromApiJsonHelper.extractIntegerSansLocaleNamed(parameterName, this.parsedCommand);
}
public boolean isChangeInBooleanParameterNamed(final String parameterName, final Boolean existingValue) {
boolean isChanged = false;
if (parameterExists(parameterName)) {
final Boolean workingValue = booleanObjectValueOfParameterNamed(parameterName);
isChanged = differenceExists(existingValue, workingValue);
}
return isChanged;
}
/**
* Returns {@link Boolean} that could possibly be null.
*/
public Boolean booleanObjectValueOfParameterNamed(final String parameterName) {
return this.fromApiJsonHelper.extractBooleanNamed(parameterName, this.parsedCommand);
}
/**
* always returns true or false
*/
public boolean booleanPrimitiveValueOfParameterNamed(final String parameterName) {
final Boolean value = this.fromApiJsonHelper.extractBooleanNamed(parameterName, this.parsedCommand);
return ObjectUtils.defaultIfNull(value, Boolean.FALSE);
}
public boolean isChangeInArrayParameterNamed(final String parameterName, final String[] existingValue) {
boolean isChanged = false;
if (parameterExists(parameterName)) {
final String[] workingValue = arrayValueOfParameterNamed(parameterName);
isChanged = differenceExists(existingValue, workingValue);
}
return isChanged;
}
public String[] arrayValueOfParameterNamed(final String parameterName) {
return this.fromApiJsonHelper.extractArrayNamed(parameterName, this.parsedCommand);
}
public JsonArray arrayOfParameterNamed(final String parameterName) {
return this.fromApiJsonHelper.extractJsonArrayNamed(parameterName, this.parsedCommand);
}
public boolean isChangeInPasswordParameterNamed(final String parameterName, final String existingValue,
final PlatformPasswordEncoder platformPasswordEncoder, final Long saltValue) {
boolean isChanged = false;
if (parameterExists(parameterName)) {
final String workingValue = passwordValueOfParameterNamed(parameterName, platformPasswordEncoder, saltValue);
isChanged = differenceExists(existingValue, workingValue);
}
return isChanged;
}
public String passwordValueOfParameterNamed(final String parameterName, final PlatformPasswordEncoder platformPasswordEncoder,
final Long saltValue) {
final String passwordPlainText = stringValueOfParameterNamed(parameterName);
final PlatformUser dummyPlatformUser = new BasicPasswordEncodablePlatformUser().setId(saltValue).setUsername("")
.setPassword(passwordPlainText);
return platformPasswordEncoder.encode(dummyPlatformUser);
}
public Locale extractLocale() {
return this.fromApiJsonHelper.extractLocaleParameter(this.parsedCommand.getAsJsonObject());
}
public void checkForUnsupportedParameters(final Type typeOfMap, final String json, final Set<String> requestDataParameters) {
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, requestDataParameters);
}
}
@@ -0,0 +1,43 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.core.data;
public class ApiErrorMessageArg {
/**
* The actual value of the parameter (if any) as passed to API.
*/
private Object value;
public static ApiErrorMessageArg from(final Object object) {
return new ApiErrorMessageArg(object);
}
public ApiErrorMessageArg(final Object object) {
this.value = object;
}
public Object getValue() {
return this.value;
}
public void setValue(final Object value) {
this.value = value;
}
}
@@ -0,0 +1,139 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.core.data;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.util.ArrayList;
import java.util.List;
public final class ApiParameterError {
/**
* A developer friendly plain English description of why the HTTP error response was returned from the API.
*/
private final String developerMessage;
/**
* A user friendly plain English description of why the HTTP error response was returned from the API that can be
* presented to end users.
*/
private final String defaultUserMessage;
/**
* A code that can be used for globalisation support by client applications of the API.
*/
private final String userMessageGlobalisationCode;
/**
* The name of the field or parameter passed to the API that this error relates to.
*/
private String parameterName;
/**
* The actual value of the parameter (if any) as passed to API.
*/
private final Object value;
/**
* Arguments related to the user error message.
*/
private final List<ApiErrorMessageArg> args;
public static ApiParameterError generalError(final String globalisationMessageCode, final String defaultUserMessage,
final Object... defaultUserMessageArgs) {
return new ApiParameterError(globalisationMessageCode, defaultUserMessage, defaultUserMessageArgs, "id", null);
}
public static ApiParameterError resourceIdentifierNotFound(final String globalisationMessageCode, final String defaultUserMessage,
final Object... defaultUserMessageArgs) {
return new ApiParameterError(globalisationMessageCode, defaultUserMessage, defaultUserMessageArgs, "id", null);
}
public static ApiParameterError parameterError(final String globalisationMessageCode, final String defaultUserMessage,
final String parameterName, final Object... defaultUserMessageArgs) {
final ApiParameterError error = new ApiParameterError(globalisationMessageCode, defaultUserMessage, defaultUserMessageArgs,
parameterName, null);
return error;
}
public static ApiParameterError parameterErrorWithValue(final String globalisationMessageCode, final String defaultUserMessage,
final String parameterName, final String value, final Object... defaultUserMessageArgs) {
final ApiParameterError error = new ApiParameterError(globalisationMessageCode, defaultUserMessage, defaultUserMessageArgs,
parameterName, value);
return error;
}
private ApiParameterError(final String globalisationMessageCode, final String defaultUserMessage, final Object[] defaultUserMessageArgs,
String parameterName, String value) {
this.userMessageGlobalisationCode = globalisationMessageCode;
this.developerMessage = defaultUserMessage;
this.defaultUserMessage = defaultUserMessage;
this.parameterName = parameterName;
this.value = value;
final List<ApiErrorMessageArg> messageArgs = new ArrayList<>();
if (defaultUserMessageArgs != null) {
for (final Object object : defaultUserMessageArgs) {
if (object instanceof LocalDate) {
final DateTimeFormatter dateFormatter = new DateTimeFormatterBuilder().appendPattern("yyyy-MM-dd").toFormatter();
final String formattedDate = dateFormatter.format((LocalDate) object);
messageArgs.add(ApiErrorMessageArg.from(formattedDate));
} else {
messageArgs.add(ApiErrorMessageArg.from(object));
}
}
}
this.args = messageArgs;
}
public String getDeveloperMessage() {
return this.developerMessage;
}
public String getDefaultUserMessage() {
return this.defaultUserMessage;
}
public String getUserMessageGlobalisationCode() {
return this.userMessageGlobalisationCode;
}
public String getParameterName() {
return this.parameterName;
}
public void setParameterName(final String parameterName) {
this.parameterName = parameterName;
}
public Object getValue() {
return this.value;
}
public List<ApiErrorMessageArg> getArgs() {
return this.args;
}
@Override
public String toString() {
return developerMessage;
}
}
@@ -0,0 +1,215 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.core.data;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import lombok.Getter;
import lombok.ToString;
import org.apache.fineract.infrastructure.core.domain.ExternalId;
/**
* Represents the successful result of an REST API call that results in processing a command.
*/
@ToString
@Getter
public class CommandProcessingResult implements Serializable {
private Long commandId;
private Long officeId;
private final Long groupId;
private final Long clientId;
private final Long loanId;
private final Long savingsId;
private final Long resourceId;
private final Long subResourceId;
private final String transactionId;
private final Map<String, Object> changes;
private final Map<String, Object> creditBureauReportData;
private final String resourceIdentifier;
private final Long productId;
private final Long gsimId;
private final Long glimId;
private Boolean rollbackTransaction;
private final ExternalId resourceExternalId;
private final ExternalId subResourceExternalId;
public static CommandProcessingResult fromCommandProcessingResult(CommandProcessingResult commandResult) {
return new CommandProcessingResult(commandResult.commandId, commandResult.officeId, commandResult.groupId, commandResult.clientId,
commandResult.loanId, commandResult.savingsId, commandResult.resourceIdentifier, commandResult.resourceId,
commandResult.transactionId, commandResult.changes, commandResult.productId, commandResult.gsimId, commandResult.glimId,
commandResult.creditBureauReportData, commandResult.rollbackTransaction, commandResult.subResourceId,
commandResult.resourceExternalId, commandResult.subResourceExternalId);
}
public static CommandProcessingResult fromCommandProcessingResult(CommandProcessingResult commandResult, final Long resourceId) {
return new CommandProcessingResult(commandResult.commandId, commandResult.officeId, commandResult.groupId, commandResult.clientId,
commandResult.loanId, commandResult.savingsId, commandResult.resourceIdentifier, resourceId, commandResult.transactionId,
commandResult.changes, commandResult.productId, commandResult.gsimId, commandResult.glimId,
commandResult.creditBureauReportData, commandResult.rollbackTransaction, commandResult.subResourceId,
commandResult.resourceExternalId, commandResult.subResourceExternalId);
}
public static CommandProcessingResult fromDetails(final Long commandId, final Long officeId, final Long groupId, final Long clientId,
final Long loanId, final Long savingsId, final String resourceIdentifier, final Long entityId, final Long gsimId,
final Long glimId, final Map<String, Object> creditBureauReportData, final String transactionId,
final Map<String, Object> changes, final Long productId, final Boolean rollbackTransaction, final Long subResourceId,
final ExternalId resourceExternalId, final ExternalId subResourceExternalId) {
return new CommandProcessingResult(commandId, officeId, groupId, clientId, loanId, savingsId, resourceIdentifier, entityId,
transactionId, changes, productId, gsimId, glimId, creditBureauReportData, rollbackTransaction, subResourceId,
resourceExternalId, subResourceExternalId);
}
public static CommandProcessingResult commandOnlyResult(final Long commandId) {
return new CommandProcessingResult(null, null, commandId, null);
}
public static CommandProcessingResult resourceResult(final Long resourceId, final Long commandId) {
return new CommandProcessingResult(resourceId, null, commandId, null);
}
public static CommandProcessingResult resourceResult(final Long resourceId, final Long commandId, final Map<String, Object> changes) {
return new CommandProcessingResult(resourceId, null, commandId, changes);
}
public static CommandProcessingResult subResourceResult(final Long resourceId, final Long subResourceId, final Long commandId) {
return new CommandProcessingResult(resourceId, subResourceId, commandId, null);
}
public static CommandProcessingResult subResourceResult(final Long resourceId, final Long subResourceId, final Long commandId,
final Map<String, Object> changes) {
return new CommandProcessingResult(resourceId, subResourceId, commandId, changes);
}
public static CommandProcessingResult withChanges(final Long resourceId, final Map<String, Object> changes) {
return new CommandProcessingResult(resourceId, null, null, changes);
}
public static CommandProcessingResult empty() {
return new CommandProcessingResult(null, null, null, null);
}
/*
* Deprecated
*/
public CommandProcessingResult(final Long entityId) {
if (entityId != null) {
this.resourceIdentifier = entityId.toString();
} else {
this.resourceIdentifier = null;
}
this.resourceId = entityId;
this.officeId = null;
this.groupId = null;
this.clientId = null;
this.loanId = null;
this.savingsId = null;
this.transactionId = null;
this.changes = new HashMap<>();
this.productId = null;
this.gsimId = null;
this.glimId = null;
this.creditBureauReportData = null;
this.subResourceId = null;
this.resourceExternalId = ExternalId.empty();
this.subResourceExternalId = ExternalId.empty();
}
private CommandProcessingResult(final Long commandId, final Long officeId, final Long groupId, final Long clientId, final Long loanId,
final Long savingsId, final String resourceIdentifier, final Long resourceId, final String transactionId,
final Map<String, Object> changesOnly, final Long productId, final Long gsimId, final Long glimId,
final Map<String, Object> creditBureauReportData, Boolean rollbackTransaction, final Long subResourceId,
final ExternalId resourceExternalId, final ExternalId subResourceExternalId) {
this.commandId = commandId;
this.officeId = officeId;
this.groupId = groupId;
this.clientId = clientId;
this.loanId = loanId;
this.savingsId = savingsId;
this.resourceIdentifier = resourceIdentifier;
this.resourceId = resourceId;
this.changes = changesOnly;
this.transactionId = transactionId;
this.productId = productId;
this.gsimId = gsimId;
this.glimId = glimId;
this.creditBureauReportData = creditBureauReportData;
this.rollbackTransaction = rollbackTransaction;
this.subResourceId = subResourceId;
this.resourceExternalId = resourceExternalId;
this.subResourceExternalId = subResourceExternalId;
}
protected CommandProcessingResult(final Long resourceId, final Long officeId, final Long commandId,
final Map<String, Object> changesOnly) {
if (resourceId != null) {
this.resourceIdentifier = resourceId.toString();
} else {
this.resourceIdentifier = null;
}
this.resourceId = resourceId;
this.officeId = officeId;
this.groupId = null;
this.clientId = null;
this.loanId = null;
this.savingsId = null;
this.transactionId = null;
this.commandId = commandId;
this.changes = changesOnly;
this.productId = null;
this.gsimId = null;
this.glimId = null;
this.creditBureauReportData = null;
this.subResourceId = null;
this.resourceExternalId = ExternalId.empty();
this.subResourceExternalId = ExternalId.empty();
}
protected CommandProcessingResult(final Long resourceId, final Long officeId, final Long commandId,
final Map<String, Object> changesOnly, long clientId) {
this(commandId, officeId, null, clientId, null, null, null, resourceId, null, changesOnly, null, null, null, null, null, null,
ExternalId.empty(), ExternalId.empty());
}
public void setOfficeId(final Long officeId) {
this.officeId = officeId;
}
public Map<String, Object> getChanges() {
Map<String, Object> checkIfEmpty = null;
if (this.changes != null && !this.changes.isEmpty()) {
checkIfEmpty = this.changes;
}
return checkIfEmpty;
}
public boolean hasChanges() {
final boolean noChanges = this.changes == null || this.changes.isEmpty();
return !noChanges;
}
public boolean isRollbackTransaction() {
return this.rollbackTransaction != null && this.rollbackTransaction;
}
public void setRollbackTransaction(Boolean rollbackTransaction) {
this.rollbackTransaction = rollbackTransaction;
}
}
@@ -0,0 +1,84 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.core.domain;
import java.io.Serial;
import java.io.Serializable;
import java.util.UUID;
import lombok.EqualsAndHashCode;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.infrastructure.core.exception.PlatformInternalServerException;
/**
* ExternalId Value object
*/
@Getter
@EqualsAndHashCode
public class ExternalId implements Serializable {
@Serial
private static final long serialVersionUID = 1;
private static final ExternalId empty = new ExternalId();
private final String value;
private ExternalId() {
this.value = null;
}
public ExternalId(String value) {
if (StringUtils.isBlank(value)) {
throw new IllegalArgumentException("error.external.id.cannot.be.blank");
}
this.value = value;
}
/**
* @return Create a new ExternalId object where value is a newly generated UUID
*/
public static ExternalId generate() {
return new ExternalId(UUID.randomUUID().toString());
}
/**
* @return Create and return an empty ExternalId object
*/
public static ExternalId empty() {
return empty;
}
/**
* @return whether value is null for the ExternalId object (return true if value is null)
*/
public boolean isEmpty() {
return value == null;
}
/**
* Throws exception if value was not set (value is null) for this object
*
* @throws PlatformInternalServerException
* if value was not set (value is null) for this object
*/
public void throwExceptionIfEmpty() {
if (isEmpty()) {
throw new PlatformInternalServerException("error.external.id.is.not.set", "Internal state violation: External id is not set");
}
}
}
@@ -0,0 +1,86 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.core.exception;
import java.util.ArrayList;
import java.util.List;
/**
* Exception with internationalization support (it's message can be translated).
*/
public abstract class AbstractPlatformException extends RuntimeException {
private static final Object[] NO_ARGS = new Object[0];
private final String globalisationMessageCode;
private final String defaultUserMessage;
private final Object[] defaultUserMessageArgs;
protected AbstractPlatformException(String globalisationMessageCode, String defaultUserMessage) {
super(defaultUserMessage);
this.globalisationMessageCode = globalisationMessageCode;
this.defaultUserMessage = defaultUserMessage;
this.defaultUserMessageArgs = NO_ARGS;
}
protected AbstractPlatformException(String globalisationMessageCode, String defaultUserMessage, Throwable cause) {
super(defaultUserMessage, cause);
this.globalisationMessageCode = globalisationMessageCode;
this.defaultUserMessage = defaultUserMessage;
this.defaultUserMessageArgs = NO_ARGS;
}
protected AbstractPlatformException(String globalisationMessageCode, String defaultUserMessage, Object[] defaultUserMessageArgs) {
super(defaultUserMessage, findThrowableCause(defaultUserMessageArgs));
this.globalisationMessageCode = globalisationMessageCode;
this.defaultUserMessage = defaultUserMessage;
this.defaultUserMessageArgs = AbstractPlatformException.filterThrowableCause(defaultUserMessageArgs);
}
private static Throwable findThrowableCause(Object[] defaultUserMessageArgs) {
for (Object defaultUserMessageArg : defaultUserMessageArgs) {
if (defaultUserMessageArg instanceof Throwable) {
return (Throwable) defaultUserMessageArg;
}
}
return null;
}
private static Object[] filterThrowableCause(Object[] defaultUserMessageArgs) {
List<Object> filteredDefaultUserMessageArgs = new ArrayList<>(defaultUserMessageArgs.length);
for (Object defaultUserMessageArg : defaultUserMessageArgs) {
if (!(defaultUserMessageArg instanceof Throwable)) {
filteredDefaultUserMessageArgs.add(defaultUserMessageArg);
}
}
return filteredDefaultUserMessageArgs.toArray();
}
public final String getGlobalisationMessageCode() {
return this.globalisationMessageCode;
}
public final String getDefaultUserMessage() {
return this.defaultUserMessage;
}
public final Object[] getDefaultUserMessageArgs() {
return this.defaultUserMessageArgs;
}
}
@@ -0,0 +1,25 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.core.exception;
/**
* A {@link RuntimeException} that is thrown in the case where invalid JSON is sent in the body of the request to the
* platform API.
*/
public class InvalidJsonException extends RuntimeException {}
@@ -0,0 +1,67 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.core.exception;
import java.util.List;
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
/**
* Exception thrown when problem with an API request to the platform.
*/
public class PlatformApiDataValidationException extends AbstractPlatformException {
private final List<ApiParameterError> errors;
/**
* Constructor. Consider simply using {@link DataValidatorBuilder#throwValidationErrors()} directly.
*
* @param errors
* list of {@link ApiParameterError} to throw
*/
public PlatformApiDataValidationException(List<ApiParameterError> errors) {
super("validation.msg.validation.errors.exist", "Validation errors exist.");
this.errors = errors;
}
public PlatformApiDataValidationException(final List<ApiParameterError> errors, Throwable cause) {
super("validation.msg.validation.errors.exist", "Validation errors exist.", cause);
this.errors = errors;
}
public PlatformApiDataValidationException(String globalisationMessageCode, String defaultUserMessage, List<ApiParameterError> errors) {
super(globalisationMessageCode, defaultUserMessage);
this.errors = errors;
}
public PlatformApiDataValidationException(String globalisationMessageCode, String defaultUserMessage, List<ApiParameterError> errors,
Throwable cause) {
super(globalisationMessageCode, defaultUserMessage, cause);
this.errors = errors;
}
public List<ApiParameterError> getErrors() {
return this.errors;
}
@Override
public String toString() {
return "PlatformApiDataValidationException{" + "errors=" + errors + '}';
}
}
@@ -0,0 +1,29 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.core.exception;
/**
* A {@link RuntimeException} thrown when unexpected server side errors happen.
*/
public class PlatformInternalServerException extends AbstractPlatformException {
public PlatformInternalServerException(String globalisationMessageCode, String defaultUserMessage, Object... defaultUserMessageArgs) {
super(globalisationMessageCode, defaultUserMessage, defaultUserMessageArgs);
}
}
@@ -0,0 +1,38 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.core.exception;
import java.util.List;
/**
* A {@link RuntimeException} that is thrown in the case where invalid parameters are sent in the body of the request to
* the platform api.
*/
public class UnsupportedParameterException extends RuntimeException {
private final List<String> unsupportedParameters;
public UnsupportedParameterException(final List<String> unsupportedParameters) {
this.unsupportedParameters = unsupportedParameters;
}
public List<String> getUnsupportedParameters() {
return this.unsupportedParameters;
}
}
@@ -0,0 +1,309 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.core.serialization;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.security.InvalidParameterException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.MonthDay;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
import org.apache.fineract.infrastructure.core.exception.UnsupportedParameterException;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
@Slf4j
@Primary
@Component
public class FromJsonHelper {
private final Gson gsonConverter;
private final JsonParserHelper helperDelegator;
public FromJsonHelper() {
this.gsonConverter = new Gson();
this.helperDelegator = new JsonParserHelper();
}
public Map<String, Boolean> extractMap(final Type typeOfMap, final String json) {
return this.gsonConverter.fromJson(json, typeOfMap);
}
public Map<String, String> extractDataMap(final Type typeOfMap, final String json) {
return this.gsonConverter.fromJson(json, typeOfMap);
}
public Map<String, Object> extractObjectMap(final Type typeOfMap, final String json) {
return this.gsonConverter.fromJson(json, typeOfMap);
}
public <T> T fromJson(final String json, final Class<T> classOfT) {
return this.gsonConverter.fromJson(json, classOfT);
}
public String toJson(final JsonElement jsonElement) {
return this.gsonConverter.toJson(jsonElement);
}
public String toJson(final Object object) {
return this.gsonConverter.toJson(object);
}
public void checkForUnsupportedParameters(final Type typeOfMap, final String json, final Collection<String> supportedParams) {
if (StringUtils.isBlank(json)) {
throw new InvalidJsonException();
}
final Map<String, Object> requestMap = this.gsonConverter.fromJson(json, typeOfMap);
final List<String> unsupportedParameterList = new ArrayList<>();
for (final String providedParameter : requestMap.keySet()) {
if (!supportedParams.contains(providedParameter)) {
unsupportedParameterList.add(providedParameter);
}
}
if (!unsupportedParameterList.isEmpty()) {
throw new UnsupportedParameterException(unsupportedParameterList);
}
}
public void checkForUnsupportedParameters(final JsonObject object, final Collection<String> supportedParams) {
if (object == null) {
throw new InvalidParameterException();
}
final Set<Map.Entry<String, JsonElement>> entries = object.entrySet();
final List<String> unsupportedParameterList = new ArrayList<>();
for (final Map.Entry<String, JsonElement> providedParameter : entries) {
if (!supportedParams.contains(providedParameter.getKey())) {
unsupportedParameterList.add(providedParameter.getKey());
}
}
if (!unsupportedParameterList.isEmpty()) {
throw new UnsupportedParameterException(unsupportedParameterList);
}
}
/**
* @param parentPropertyName
* The full json path to this property,the value is appended to the parameter name while generating an
* error message <br>
* Ex: property "name" in Object "person" would be named as "person.name"
* @param object
* @param supportedParams
*/
@SuppressWarnings("AvoidHidingCauseException")
public void checkForUnsupportedNestedParameters(final String parentPropertyName, final JsonObject object,
final Set<String> supportedParams) {
try {
checkForUnsupportedParameters(object, supportedParams);
} catch (UnsupportedParameterException exception) {
List<String> unsupportedParameters = exception.getUnsupportedParameters();
List<String> updatedUnsupportedParameters = new ArrayList<>();
for (String unsupportedParameter : unsupportedParameters) {
String updatedUnsupportedParameter = parentPropertyName + "." + unsupportedParameter;
updatedUnsupportedParameters.add(updatedUnsupportedParameter);
}
throw new UnsupportedParameterException(updatedUnsupportedParameters);
}
}
public JsonElement parse(final String json) {
JsonElement parsedElement = null;
if (StringUtils.isNotBlank(json)) {
parsedElement = JsonParser.parseString(json);
}
return parsedElement;
}
public boolean parameterExists(final String parameterName, final JsonElement element) {
return this.helperDelegator.parameterExists(parameterName, element);
}
public String extractStringNamed(final String parameterName, final JsonElement element) {
return this.helperDelegator.extractStringNamed(parameterName, element, new HashSet<String>());
}
public String extractStringNamed(final String parameterName, final JsonElement element, final Set<String> parametersPassedInRequest) {
return this.helperDelegator.extractStringNamed(parameterName, element, parametersPassedInRequest);
}
public Long extractLongNamed(final String parameterName, final JsonElement element) {
return this.helperDelegator.extractLongNamed(parameterName, element, new HashSet<String>());
}
public Long extractLongNamed(final String parameterName, final JsonElement element, final Set<String> parametersPassedInRequest) {
return this.helperDelegator.extractLongNamed(parameterName, element, parametersPassedInRequest);
}
public JsonArray extractJsonArrayNamed(final String parameterName, final JsonElement element) {
return this.helperDelegator.extractJsonArrayNamed(parameterName, element);
}
public String[] extractArrayNamed(final String parameterName, final JsonElement element) {
return this.helperDelegator.extractArrayNamed(parameterName, element, new HashSet<String>());
}
public String[] extractArrayNamed(final String parameterName, final JsonElement element, final Set<String> parametersPassedInRequest) {
return this.helperDelegator.extractArrayNamed(parameterName, element, parametersPassedInRequest);
}
public Boolean extractBooleanNamed(final String parameterName, final JsonElement element) {
return this.helperDelegator.extractBooleanNamed(parameterName, element, new HashSet<String>());
}
public Boolean extractBooleanNamed(final String parameterName, final JsonElement element, final Set<String> parametersPassedInRequest) {
return this.helperDelegator.extractBooleanNamed(parameterName, element, parametersPassedInRequest);
}
public MonthDay extractMonthDayNamed(final String parameterName, final JsonElement element) {
return this.helperDelegator.extractMonthDayNamed(parameterName, element);
}
public MonthDay extractMonthDayNamed(final String parameterName, final JsonObject object, final String dateFormat,
final Locale clientApplicationLocale) {
return this.helperDelegator.extractMonthDayNamed(parameterName, object, dateFormat, clientApplicationLocale);
}
public LocalDate extractLocalDateNamed(final String parameterName, final JsonElement element) {
return this.helperDelegator.extractLocalDateNamed(parameterName, element, new HashSet<>());
}
public LocalTime extractLocalTimeNamed(final String parameterName, final JsonElement element) {
return this.helperDelegator.extractLocalTimeNamed(parameterName, element, new HashSet<>());
}
public LocalDateTime extractLocalDateTimeNamed(final String parameterName, final JsonElement element) {
return this.helperDelegator.extractLocalDateTimeNamed(parameterName, element, new HashSet<>());
}
public LocalTime extractLocalTimeNamed(final String parameterName, final JsonElement element, final String dateFormat,
final Locale locale) {
return this.helperDelegator.extractLocalTimeNamed(parameterName, element, dateFormat, locale, new HashSet<>());
}
public LocalTime extractLocalTimeNamed(final String parameterName, final JsonElement element, String timeFormat) {
return this.helperDelegator.extractLocalTimeNamed(parameterName, element, timeFormat, new HashSet<>());
}
public LocalDateTime extractLocalDateTimeNamed(final String parameterName, final JsonElement element, final String dateFormat,
final Locale locale) {
return this.helperDelegator.extractLocalDateTimeNamed(parameterName, element, dateFormat, locale, new HashSet<>());
}
public LocalDateTime extractLocalDateTimeNamed(final String parameterName, final JsonElement element, String timeFormat) {
return this.helperDelegator.extractLocalDateTimeNamed(parameterName, element, timeFormat, new HashSet<>());
}
public LocalDate extractLocalDateNamed(final String parameterName, final JsonElement element, final String dateFormat,
final Locale locale) {
return this.helperDelegator.extractLocalDateNamed(parameterName, element.getAsJsonObject(), dateFormat, locale, new HashSet<>());
}
public LocalDate extractLocalDateNamed(final String parameterName, final JsonElement element,
final Set<String> parametersPassedInRequest) {
return this.helperDelegator.extractLocalDateNamed(parameterName, element, parametersPassedInRequest);
}
public LocalDate extractLocalDateAsArrayNamed(final String parameterName, final JsonElement element,
final Set<String> parametersPassedInRequest) {
return this.helperDelegator.extractLocalDateAsArrayNamed(parameterName, element, parametersPassedInRequest);
}
public BigDecimal extractBigDecimalWithLocaleNamed(final String parameterName, final JsonElement element) {
return this.helperDelegator.extractBigDecimalWithLocaleNamed(parameterName, element, new HashSet<String>());
}
public BigDecimal extractBigDecimalWithLocaleNamed(final String parameterName, final JsonElement element,
final Set<String> parametersPassedInRequest) {
return this.helperDelegator.extractBigDecimalWithLocaleNamed(parameterName, element, parametersPassedInRequest);
}
public BigDecimal extractBigDecimalNamed(final String parameterName, final JsonElement element, final Locale locale) {
return this.helperDelegator.extractBigDecimalNamed(parameterName, element.getAsJsonObject(), locale, new HashSet<String>());
}
public BigDecimal extractBigDecimalNamed(final String parameterName, final JsonElement element,
final Set<String> parametersPassedInRequest) {
return this.helperDelegator.extractBigDecimalNamed(parameterName, element.getAsJsonObject(), Locale.US, parametersPassedInRequest);
}
public Integer extractIntegerWithLocaleNamed(final String parameterName, final JsonElement element) {
return this.helperDelegator.extractIntegerWithLocaleNamed(parameterName, element.getAsJsonObject(), new HashSet<String>());
}
public Integer extractIntegerSansLocaleNamed(final String parameterName, final JsonElement element) {
return this.helperDelegator.extractIntegerSansLocaleNamed(parameterName, element.getAsJsonObject(), new HashSet<String>());
}
public Integer extractIntegerWithLocaleNamed(final String parameterName, final JsonElement element,
final Set<String> parametersPassedInRequest) {
return this.helperDelegator.extractIntegerWithLocaleNamed(parameterName, element.getAsJsonObject(), parametersPassedInRequest);
}
public Integer extractIntegerNamed(final String parameterName, final JsonElement element, final Locale locale) {
return this.helperDelegator.extractIntegerNamed(parameterName, element.getAsJsonObject(), locale, new HashSet<String>());
}
public Integer extractIntegerNamed(final String parameterName, final JsonElement element, final Set<String> parametersPassedInRequest) {
return this.helperDelegator.extractIntegerNamed(parameterName, element.getAsJsonObject(), Locale.US, parametersPassedInRequest);
}
public Locale extractLocaleParameter(final JsonObject element) {
return this.helperDelegator.extractLocaleParameter(element);
}
public String extractDateFormatParameter(final JsonObject element) {
return this.helperDelegator.extractDateFormatParameter(element);
}
public String extractMonthDayFormatParameter(final JsonObject element) {
return this.helperDelegator.extractMonthDayFormatParameter(element);
}
public JsonObject extractJsonObjectNamed(final String parameterName, final JsonElement element) {
return this.helperDelegator.extractJsonObjectNamed(parameterName, element);
}
public Gson getGsonConverter() {
return this.gsonConverter;
}
}
@@ -0,0 +1,795 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.core.serialization;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.text.ParseException;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.MonthDay;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoField;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.springframework.format.number.NumberStyleFormatter;
/**
* Helper class to extract values of json named attributes.
*/
public class JsonParserHelper {
public boolean parameterExists(final String parameterName, final JsonElement element) {
if (element == null) {
return false;
}
return element.getAsJsonObject().has(parameterName);
}
public Boolean extractBooleanNamed(final String parameterName, final JsonElement element, final Set<String> requestParamatersDetected) {
Boolean value = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) {
requestParamatersDetected.add(parameterName);
final JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive();
value = primitive.getAsBoolean();
}
}
return value;
}
public Long extractLongNamed(final String parameterName, final JsonElement element, final Set<String> parametersPassedInRequest) {
Long longValue = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) {
parametersPassedInRequest.add(parameterName);
final JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive();
final String stringValue = primitive.getAsString();
if (StringUtils.isNotBlank(stringValue)) {
longValue = Long.valueOf(stringValue);
}
}
}
return longValue;
}
public String extractStringNamed(final String parameterName, final JsonElement element, final Set<String> parametersPassedInRequest) {
String stringValue = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) {
parametersPassedInRequest.add(parameterName);
final JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive();
final String valueAsString = primitive.getAsString();
if (StringUtils.isNotBlank(valueAsString)) {
stringValue = valueAsString;
}
}
}
return stringValue;
}
public BigDecimal extractBigDecimalWithLocaleNamed(final String parameterName, final JsonElement element,
final Set<String> modifiedParameters) {
BigDecimal value = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
final Locale locale = extractLocaleValue(object);
value = extractBigDecimalNamed(parameterName, object, locale, modifiedParameters);
}
return value;
}
public BigDecimal extractBigDecimalNamed(final String parameterName, final JsonObject element, final Locale locale,
final Set<String> modifiedParameters) {
BigDecimal value = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) {
modifiedParameters.add(parameterName);
final JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive();
if (!primitive.isJsonNull()) {
if (primitive.isNumber()) {
value = primitive.getAsBigDecimal();
} else {
final String valueAsString = primitive.getAsString();
if (StringUtils.isNotBlank(valueAsString)) {
value = convertFrom(valueAsString, parameterName, locale);
}
}
}
}
}
return value;
}
public Integer extractIntegerWithLocaleNamed(final String parameterName, final JsonElement element,
final Set<String> modifiedParameters) {
Integer value = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
final Locale locale = extractLocaleValue(object);
value = extractIntegerNamed(parameterName, object, locale, modifiedParameters);
}
return value;
}
public Integer extractIntegerNamed(final String parameterName, final JsonElement element, final Locale locale,
final Set<String> modifiedParameters) {
Integer value = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) {
modifiedParameters.add(parameterName);
final JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive();
final String valueAsString = primitive.getAsString();
if (StringUtils.isNotBlank(valueAsString)) {
value = convertToInteger(valueAsString, parameterName, locale);
}
}
}
return value;
}
/**
* Method used to extract integers from unformatted strings. Ex: "1" , "100002" etc
*
* Please note that this method does not support extracting Integers from locale specific formatted strings Ex
* "1,000" etc
*
* @param parameterName
* @param element
* @param parametersPassedInRequest
* @return
*/
public Integer extractIntegerSansLocaleNamed(final String parameterName, final JsonElement element,
final Set<String> parametersPassedInRequest) {
Integer intValue = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) {
parametersPassedInRequest.add(parameterName);
final JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive();
final String stringValue = primitive.getAsString();
if (StringUtils.isNotBlank(stringValue)) {
intValue = convertToIntegerSanLocale(stringValue, parameterName);
}
}
}
return intValue;
}
public String extractDateFormatParameter(final JsonObject element) {
String value = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
final String dateFormatParameter = "dateFormat";
if (object.has(dateFormatParameter) && object.get(dateFormatParameter).isJsonPrimitive()) {
final JsonPrimitive primitive = object.get(dateFormatParameter).getAsJsonPrimitive();
value = primitive.getAsString();
}
}
return value;
}
public String extractTimeFormatParameter(final JsonObject element) {
String value = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
final String timeFormatParameter = "timeFormat";
if (object.has(timeFormatParameter) && object.get(timeFormatParameter).isJsonPrimitive()) {
final JsonPrimitive primitive = object.get(timeFormatParameter).getAsJsonPrimitive();
value = primitive.getAsString();
}
}
return value;
}
public String extractMonthDayFormatParameter(final JsonObject element) {
String value = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
final String monthDayFormatParameter = "monthDayFormat";
if (object.has(monthDayFormatParameter) && object.get(monthDayFormatParameter).isJsonPrimitive()) {
final JsonPrimitive primitive = object.get(monthDayFormatParameter).getAsJsonPrimitive();
value = primitive.getAsString();
}
}
return value;
}
public Locale extractLocaleParameter(final JsonObject element) {
Locale clientApplicationLocale = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
String locale = null;
final String localeParameter = "locale";
if (object.has(localeParameter) && object.get(localeParameter).isJsonPrimitive()) {
final JsonPrimitive primitive = object.get(localeParameter).getAsJsonPrimitive();
locale = primitive.getAsString();
clientApplicationLocale = localeFromString(locale);
}
}
return clientApplicationLocale;
}
public String[] extractArrayNamed(final String parameterName, final JsonElement element, final Set<String> parametersPassedInRequest) {
String[] arrayValue = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
if (object.has(parameterName)) {
parametersPassedInRequest.add(parameterName);
final JsonArray array = object.get(parameterName).getAsJsonArray();
arrayValue = new String[array.size()];
for (int i = 0; i < array.size(); i++) {
arrayValue[i] = array.get(i).getAsString();
}
}
}
return arrayValue;
}
public JsonArray extractJsonArrayNamed(final String parameterName, final JsonElement element) {
JsonArray jsonArray = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
if (object.has(parameterName)) {
jsonArray = object.get(parameterName).getAsJsonArray();
}
}
return jsonArray;
}
public JsonObject extractJsonObjectNamed(final String parameterName, final JsonElement element) {
JsonObject jsonObject = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
if (object.has(parameterName)) {
jsonObject = object.get(parameterName).getAsJsonObject();
}
}
return jsonObject;
}
/**
* Used with the local date is in array format
*/
public LocalDate extractLocalDateAsArrayNamed(final String parameterName, final JsonElement element,
final Set<String> parametersPassedInCommand) {
LocalDate value = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
if (object.has(parameterName) && object.get(parameterName).isJsonArray()) {
parametersPassedInCommand.add(parameterName);
final JsonArray dateArray = object.get(parameterName).getAsJsonArray();
final int year = dateArray.get(0).getAsInt();
final int month = dateArray.get(1).getAsInt();
final int day = dateArray.get(2).getAsInt();
value = LocalDate.of(year, month, day);
}
}
return value;
}
public MonthDay extractMonthDayNamed(final String parameterName, final JsonElement element) {
MonthDay value = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
final String monthDayFormat = extractMonthDayFormatParameter(object);
final Locale clientApplicationLocale = extractLocaleParameter(object);
value = extractMonthDayNamed(parameterName, object, monthDayFormat, clientApplicationLocale);
}
return value;
}
public MonthDay extractMonthDayNamed(final String parameterName, final JsonObject element, final String dateFormat,
final Locale clientApplicationLocale) {
MonthDay value = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) {
final JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive();
final String valueAsString = primitive.getAsString();
if (StringUtils.isNotBlank(valueAsString)) {
try {
final DateTimeFormatter formatter = new DateTimeFormatterBuilder().parseCaseInsensitive().parseLenient()
.appendPattern(dateFormat).toFormatter(clientApplicationLocale);
value = MonthDay.parse(valueAsString, formatter);
} catch (final IllegalArgumentException e) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.month.day",
"The parameter `" + parameterName + "` is invalid based on the monthDayFormat: `" + dateFormat
+ "` and locale: `" + clientApplicationLocale + "` provided:",
parameterName, valueAsString, dateFormat);
dataValidationErrors.add(error);
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors, e);
}
}
}
}
return value;
}
public LocalDate extractLocalDateNamed(final String parameterName, final JsonElement element,
final Set<String> parametersPassedInCommand) {
LocalDate value = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
final String dateFormat = extractDateFormatParameter(object);
final Locale clientApplicationLocale = extractLocaleParameter(object);
value = extractLocalDateNamed(parameterName, object, dateFormat, clientApplicationLocale, parametersPassedInCommand);
}
return value;
}
public LocalTime extractLocalTimeNamed(final String parameterName, final JsonElement element,
final Set<String> parametersPassedInCommand) {
LocalTime value = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
value = extractLocalTimeNamed(parameterName, element, extractTimeFormatParameter(object), parametersPassedInCommand);
}
return value;
}
public LocalDateTime extractLocalDateTimeNamed(final String parameterName, final JsonElement element,
final Set<String> parametersPassedInCommand) {
LocalDateTime value = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
value = extractLocalDateTimeNamed(parameterName, element, extractTimeFormatParameter(object), parametersPassedInCommand);
}
return value;
}
public LocalTime extractLocalTimeNamed(final String parameterName, final JsonElement element, String timeFormat,
final Set<String> parametersPassedInCommand) {
LocalTime value = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
final Locale clientApplicationLocale = extractLocaleParameter(object);
value = extractLocalTimeNamed(parameterName, object, timeFormat, clientApplicationLocale, parametersPassedInCommand);
}
return value;
}
public LocalDateTime extractLocalDateTimeNamed(final String parameterName, final JsonElement element, String timeFormat,
final Set<String> parametersPassedInCommand) {
LocalDateTime value = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
final Locale clientApplicationLocale = extractLocaleParameter(object);
value = extractLocalDateTimeNamed(parameterName, object, timeFormat, clientApplicationLocale, parametersPassedInCommand);
}
return value;
}
public LocalTime extractLocalTimeNamed(final String parameterName, final JsonElement element, final String timeFormat,
final Locale clientApplicationLocale, final Set<String> parametersPassedInCommand) {
LocalTime value = null;
String timeValueAsString = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) {
parametersPassedInCommand.add(parameterName);
try {
DateTimeFormatter timeFormtter = DateTimeFormatter.ofPattern(timeFormat);
final JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive();
timeValueAsString = primitive.getAsString();
if (StringUtils.isNotBlank(timeValueAsString)) {
value = LocalTime.parse(timeValueAsString, timeFormtter);
}
} catch (IllegalArgumentException e) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final String defaultMessage = new StringBuilder("The parameter `" + timeValueAsString + "` is not in correct format.")
.toString();
final ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.TimeFormat", defaultMessage,
parameterName);
dataValidationErrors.add(error);
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors, e);
}
}
}
return value;
}
public LocalDateTime extractLocalDateTimeNamed(final String parameterName, final JsonElement element, final String timeFormat,
final Locale clientApplicationLocale, final Set<String> parametersPassedInCommand) {
LocalDateTime value = null;
String timeValueAsString = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) {
parametersPassedInCommand.add(parameterName);
try {
DateTimeFormatter timeFormtter = DateTimeFormatter.ofPattern(timeFormat);
final JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive();
timeValueAsString = primitive.getAsString();
if (StringUtils.isNotBlank(timeValueAsString)) {
value = LocalDateTime.parse(timeValueAsString, timeFormtter);
}
} catch (IllegalArgumentException e) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final String defaultMessage = new StringBuilder("The parameter `" + timeValueAsString + "` is not in correct format.")
.toString();
final ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.TimeFormat", defaultMessage,
parameterName);
dataValidationErrors.add(error);
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors, e);
}
}
}
return value;
}
public LocalDate extractLocalDateNamed(final String parameterName, final JsonElement element, final String dateFormat,
final Locale clientApplicationLocale, final Set<String> parametersPassedInCommand) {
LocalDate value = null;
if (element.isJsonObject()) {
final JsonObject object = element.getAsJsonObject();
if (object.has(parameterName) && object.get(parameterName).isJsonPrimitive()) {
parametersPassedInCommand.add(parameterName);
final JsonPrimitive primitive = object.get(parameterName).getAsJsonPrimitive();
final String valueAsString = primitive.getAsString();
if (StringUtils.isNotBlank(valueAsString)) {
value = convertFrom(valueAsString, parameterName, dateFormat, clientApplicationLocale);
}
}
}
return value;
}
public static LocalDate convertFrom(final String dateAsString, final String parameterName, final String dateFormat,
final Locale clientApplicationLocale) {
return convertDateTimeFrom(dateAsString, parameterName, dateFormat, clientApplicationLocale).toLocalDate();
}
public static LocalDateTime convertDateTimeFrom(final String dateTimeAsString, final String parameterName, final String dateTimeFormat,
final Locale clientApplicationLocale) {
validateDateFormatAndLocale(parameterName, dateTimeFormat, clientApplicationLocale);
LocalDateTime eventLocalDateTime = null;
if (StringUtils.isNotBlank(dateTimeAsString)) {
try {
DateTimeFormatter formatter = new DateTimeFormatterBuilder().parseCaseInsensitive().parseLenient()
.appendPattern(dateTimeFormat).optionalStart().appendPattern(" HH:mm:ss").optionalEnd()
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0).parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0).toFormatter(clientApplicationLocale);
eventLocalDateTime = LocalDateTime.parse(dateTimeAsString, formatter);
} catch (final IllegalArgumentException | DateTimeParseException e) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final ApiParameterError error = ApiParameterError
.parameterError("validation.msg.invalid.dateFormat.format",
"The parameter `" + parameterName + "` is invalid based on the dateFormat: `" + dateTimeFormat
+ "` and locale: `" + clientApplicationLocale + "` provided:",
parameterName, eventLocalDateTime, dateTimeFormat);
dataValidationErrors.add(error);
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors, e);
}
}
return eventLocalDateTime;
}
private static void validateDateFormatAndLocale(final String parameterName, final String dateFormat,
final Locale clientApplicationLocale) {
if (StringUtils.isBlank(dateFormat) || clientApplicationLocale == null) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
if (StringUtils.isBlank(dateFormat)) {
final String defaultMessage = new StringBuilder(
"The parameter `" + parameterName + "` requires a `dateFormat` parameter to be passed with it.").toString();
final ApiParameterError error = ApiParameterError.parameterError("validation.msg.missing.dateFormat.parameter",
defaultMessage, parameterName);
dataValidationErrors.add(error);
}
if (clientApplicationLocale == null) {
final String defaultMessage = new StringBuilder(
"The parameter `" + parameterName + "` requires a `locale` parameter to be passed with it.").toString();
final ApiParameterError error = ApiParameterError.parameterError("validation.msg.missing.locale.parameter", defaultMessage,
parameterName);
dataValidationErrors.add(error);
}
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors);
}
}
public Integer convertToInteger(final String numericalValueFormatted, final String parameterName,
final Locale clientApplicationLocale) {
if (clientApplicationLocale == null) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final String defaultMessage = new StringBuilder(
"The parameter `" + parameterName + "` requires a `locale` parameter to be passed with it.").toString();
final ApiParameterError error = ApiParameterError.parameterError("validation.msg.missing.locale.parameter", defaultMessage,
parameterName);
dataValidationErrors.add(error);
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors);
}
try {
Integer number = null;
if (StringUtils.isNotBlank(numericalValueFormatted)) {
String source = numericalValueFormatted.trim();
final NumberFormat format = NumberFormat.getInstance(clientApplicationLocale);
final DecimalFormat df = (DecimalFormat) format;
final DecimalFormatSymbols symbols = df.getDecimalFormatSymbols();
df.setParseBigDecimal(true);
// http://bugs.sun.com/view_bug.do?bug_id=4510618
final char groupingSeparator = symbols.getGroupingSeparator();
if (groupingSeparator == '\u00a0') {
source = source.replaceAll(" ", Character.toString('\u00a0'));
}
final Number parsedNumber = df.parse(source);
final double parsedNumberDouble = parsedNumber.doubleValue();
final int parsedNumberInteger = parsedNumber.intValue();
if (source.contains(Character.toString(symbols.getDecimalSeparator()))) {
throw new ParseException(source, 0);
}
if (!Double.valueOf(parsedNumberDouble).equals(Double.valueOf(Integer.valueOf(parsedNumberInteger)))) {
throw new ParseException(source, 0);
}
number = parsedNumber.intValue();
}
return number;
} catch (final ParseException e) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final ApiParameterError error = ApiParameterError.parameterErrorWithValue("validation.msg.invalid.integer.format",
"The parameter `" + parameterName + "` has value: " + numericalValueFormatted
+ " which is invalid integer value for provided locale of [" + clientApplicationLocale.toString() + "].",
parameterName, numericalValueFormatted, numericalValueFormatted, clientApplicationLocale);
dataValidationErrors.add(error);
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors, e);
}
}
public Integer convertToIntegerSanLocale(final String numericalValueFormatted, final String parameterName) {
try {
Integer number = null;
if (StringUtils.isNotBlank(numericalValueFormatted)) {
number = Integer.valueOf(numericalValueFormatted);
}
return number;
} catch (final NumberFormatException e) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final ApiParameterError error = ApiParameterError.parameterErrorWithValue("validation.msg.invalid.integer",
"The parameter `" + parameterName + "` has value: " + numericalValueFormatted + " which is invalid integer.",
parameterName, numericalValueFormatted, numericalValueFormatted);
dataValidationErrors.add(error);
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors, e);
}
}
public BigDecimal convertFrom(final String numericalValueFormatted, final String parameterName, final Locale clientApplicationLocale) {
if (clientApplicationLocale == null) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final String defaultMessage = new StringBuilder(
"The parameter `" + parameterName + "` requires a `locale` parameter to be passed with it.").toString();
final ApiParameterError error = ApiParameterError.parameterError("validation.msg.missing.locale.parameter", defaultMessage,
parameterName);
dataValidationErrors.add(error);
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors);
}
try {
BigDecimal number = null;
if (StringUtils.isNotBlank(numericalValueFormatted)) {
String source = numericalValueFormatted.trim();
final NumberFormat format = NumberFormat.getNumberInstance(clientApplicationLocale);
final DecimalFormat df = (DecimalFormat) format;
final DecimalFormatSymbols symbols = df.getDecimalFormatSymbols();
// http://bugs.sun.com/view_bug.do?bug_id=4510618
final char groupingSeparator = symbols.getGroupingSeparator();
if (groupingSeparator == '\u00a0') {
source = source.replaceAll(" ", Character.toString('\u00a0'));
}
final NumberStyleFormatter numberFormatter = new NumberStyleFormatter();
final Number parsedNumber = numberFormatter.parse(source, clientApplicationLocale);
if (parsedNumber instanceof BigDecimal) {
number = (BigDecimal) parsedNumber;
} else {
number = BigDecimal.valueOf(parsedNumber.doubleValue());
}
}
return number;
} catch (final ParseException e) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final ApiParameterError error = ApiParameterError.parameterErrorWithValue("validation.msg.invalid.decimal.format",
"The parameter `" + parameterName + "` has value: " + numericalValueFormatted
+ " which is invalid decimal value for provided locale of [" + clientApplicationLocale + "].",
parameterName, numericalValueFormatted, numericalValueFormatted, clientApplicationLocale);
dataValidationErrors.add(error);
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors, e);
}
}
/***
* TODO: Vishwas move all Locale related code to a separate Utils class
***/
public static Locale localeFromString(final String localeAsString) {
if (StringUtils.isBlank(localeAsString)) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.locale.format",
"The parameter `locale` is invalid. It cannot be blank.", "locale");
dataValidationErrors.add(error);
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors);
}
String languageCode = "";
String countryCode = "";
String variantCode = "";
final String[] localeParts = localeAsString.split("_");
if (localeParts != null && localeParts.length == 1) {
languageCode = localeParts[0];
}
if (localeParts != null && localeParts.length == 2) {
languageCode = localeParts[0];
countryCode = localeParts[1];
}
if (localeParts != null && localeParts.length == 3) {
languageCode = localeParts[0];
countryCode = localeParts[1];
variantCode = localeParts[2];
}
return localeFrom(languageCode, countryCode, variantCode);
}
private static Locale localeFrom(final String languageCode, final String courntryCode, final String variantCode) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final List<String> allowedLanguages = Arrays.asList(Locale.getISOLanguages());
if (!allowedLanguages.contains(languageCode.toLowerCase())) {
final ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.locale.format",
"The parameter `locale` has an invalid language value " + languageCode + " .", "locale", languageCode);
dataValidationErrors.add(error);
}
if (StringUtils.isNotBlank(courntryCode.toUpperCase())) {
final List<String> allowedCountries = Arrays.asList(Locale.getISOCountries());
if (!allowedCountries.contains(courntryCode)) {
final ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.locale.format",
"The parameter `locale` has an invalid country value " + courntryCode + " .", "locale", courntryCode);
dataValidationErrors.add(error);
}
}
if (!dataValidationErrors.isEmpty()) {
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidationErrors);
}
return new Locale(languageCode.toLowerCase(), courntryCode.toUpperCase(), variantCode);
}
private Locale extractLocaleValue(final JsonObject object) {
Locale clientApplicationLocale = null;
String locale = null;
if (object.has("locale") && object.get("locale").isJsonPrimitive()) {
final JsonPrimitive primitive = object.get("locale").getAsJsonPrimitive();
locale = primitive.getAsString();
clientApplicationLocale = localeFromString(locale);
}
return clientApplicationLocale;
}
}
@@ -0,0 +1,65 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.security.domain;
import java.util.Collection;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.springframework.security.core.GrantedAuthority;
@Setter
@NoArgsConstructor
@Accessors(chain = true)
public class BasicPasswordEncodablePlatformUser implements PlatformUser {
@Getter
private Long id;
@Getter(onMethod = @__(@Override))
private String username;
@Getter(onMethod = @__(@Override))
private String password;
@Override
public Collection<GrantedAuthority> getAuthorities() {
return null;
}
@Override
public boolean isAccountNonExpired() {
return false;
}
@Override
public boolean isAccountNonLocked() {
return false;
}
@Override
public boolean isCredentialsNonExpired() {
return false;
}
@Override
public boolean isEnabled() {
return false;
}
}
@@ -0,0 +1,28 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.security.domain;
import org.springframework.security.core.userdetails.UserDetails;
/**
* Interface to protect platform from implementation detail of spring security.
*/
public interface PlatformUser extends UserDetails {
}
@@ -0,0 +1,26 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.infrastructure.security.service;
import org.apache.fineract.infrastructure.security.domain.PlatformUser;
public interface PlatformPasswordEncoder {
String encode(PlatformUser appUser);
}