MIFOSX-259: make so loanTenantById gets cached correctly - also introduce delegatingCacheManager to allow us to introduce api and configuration to support switching cache solution runtime. At present caching is disabled through use of NoOpCacheManager.
This commit is contained in:
+29
@@ -0,0 +1,29 @@
|
||||
package org.mifosplatform.infrastructure.cache;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.annotation.CachingConfigurer;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.cache.interceptor.DefaultKeyGenerator;
|
||||
import org.springframework.cache.interceptor.KeyGenerator;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
@EnableCaching
|
||||
public class PlatformCacheConfiguration implements CachingConfigurer {
|
||||
|
||||
@Autowired
|
||||
private RuntimeDelegatingCacheManager delegatingCacheManager;
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
public CacheManager cacheManager() {
|
||||
return this.delegatingCacheManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyGenerator keyGenerator() {
|
||||
return new DefaultKeyGenerator();
|
||||
}
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package org.mifosplatform.infrastructure.cache;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.Cache;
|
||||
import org.springframework.cache.CacheManager;
|
||||
import org.springframework.cache.ehcache.EhCacheCacheManager;
|
||||
import org.springframework.cache.support.NoOpCacheManager;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* At present this implementation of {@link CacheManager} just delegates to the
|
||||
* real {@link CacheManager} to use.
|
||||
*
|
||||
* By default it is {@link NoOpCacheManager} but we can change that by checking
|
||||
* some persisted configuration in the database on startup and allow user to
|
||||
* switch implementation through UI/API
|
||||
*/
|
||||
@Component
|
||||
public class RuntimeDelegatingCacheManager implements CacheManager {
|
||||
|
||||
private final CacheManager ehcacheCacheManager;
|
||||
private final CacheManager noOpCacheManager = new NoOpCacheManager();
|
||||
private CacheManager currentCacheManager = this.noOpCacheManager;
|
||||
|
||||
@Autowired
|
||||
public RuntimeDelegatingCacheManager(final EhCacheCacheManager ehCacheCacheManager) {
|
||||
this.ehcacheCacheManager = ehCacheCacheManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cache getCache(final String name) {
|
||||
return this.currentCacheManager.getCache(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<String> getCacheNames() {
|
||||
return this.currentCacheManager.getCacheNames();
|
||||
}
|
||||
|
||||
// TODO - Annuruddha - you need to create API to call to switch caching
|
||||
// approach from NoOp to Single instance Echache - we can tackle the
|
||||
// distributed cache through memcache then - didnt see the configuration for
|
||||
// that.
|
||||
// example method to switch caching mechanism used
|
||||
private void switchToEhCache() {
|
||||
this.currentCacheManager = this.ehcacheCacheManager;
|
||||
}
|
||||
}
|
||||
+25
-53
@@ -5,53 +5,23 @@
|
||||
*/
|
||||
package org.mifosplatform.infrastructure.core.domain;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
public class MifosPlatformTenant {
|
||||
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
private final Long id;
|
||||
private final String tenantIdentifier;
|
||||
private final String name;
|
||||
private final String schemaName;
|
||||
private final String schemaServer;
|
||||
private final String schemaServerPort;
|
||||
private final String schemaUsername;
|
||||
private final String schemaPassword;
|
||||
private final String timezoneId;
|
||||
private final boolean autoUpdateEnabled;
|
||||
|
||||
|
||||
@Entity
|
||||
@Table(name = "tenants")
|
||||
public class MifosPlatformTenant extends AbstractPersistable<Long>{
|
||||
|
||||
@Column(name="identifier")
|
||||
private String tenantIdentifier;
|
||||
|
||||
@Column(name = "name")
|
||||
private String name;
|
||||
|
||||
@Column(name = "schema_name")
|
||||
private String schemaName;
|
||||
|
||||
@Column(name = "schema_server")
|
||||
private String schemaServer;
|
||||
|
||||
@Column(name = "schema_server_port")
|
||||
private String schemaServerPort;
|
||||
|
||||
@Column(name = "schema_username")
|
||||
private String schemaUsername;
|
||||
|
||||
@Column(name = "schema_password")
|
||||
private String schemaPassword;
|
||||
|
||||
@Column(name = "timezone_id")
|
||||
private String timezoneId;
|
||||
|
||||
@Column(name = "auto_update")
|
||||
private boolean autoUpdateEnabled;
|
||||
|
||||
|
||||
public MifosPlatformTenant() {
|
||||
|
||||
}
|
||||
|
||||
public MifosPlatformTenant(final Long id,final String tenantIdentifier, final String name, final String schemaName, final String schemaServer,
|
||||
final String schemaServerPort, final String schemaUsername, final String schemaPassword, String timezoneId,
|
||||
final boolean autoUpdateEnabled) {
|
||||
setId(id);
|
||||
public MifosPlatformTenant(final Long id, final String tenantIdentifier, final String name, final String schemaName,
|
||||
final String schemaServer, final String schemaServerPort, final String schemaUsername, final String schemaPassword,
|
||||
final String timezoneId, final boolean autoUpdateEnabled) {
|
||||
this.id = id;
|
||||
this.tenantIdentifier = tenantIdentifier;
|
||||
this.name = name;
|
||||
this.schemaName = schemaName;
|
||||
@@ -61,22 +31,24 @@ public class MifosPlatformTenant extends AbstractPersistable<Long>{
|
||||
this.schemaPassword = schemaPassword;
|
||||
this.timezoneId = timezoneId;
|
||||
this.autoUpdateEnabled = autoUpdateEnabled;
|
||||
|
||||
}
|
||||
|
||||
public String databaseURL() {
|
||||
String url = new StringBuilder("jdbc:mysql://").append(schemaServer).append(':').append(schemaServerPort).append('/')
|
||||
.append(schemaName).toString();
|
||||
final String url = new StringBuilder("jdbc:mysql://").append(this.schemaServer).append(':').append(this.schemaServerPort)
|
||||
.append('/').append(this.schemaName).toString();
|
||||
return url;
|
||||
}
|
||||
|
||||
|
||||
public Long getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
public String getTenantIdentifier() {
|
||||
return this.tenantIdentifier;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public String getSchemaName() {
|
||||
@@ -84,15 +56,15 @@ public class MifosPlatformTenant extends AbstractPersistable<Long>{
|
||||
}
|
||||
|
||||
public String getSchemaUsername() {
|
||||
return schemaUsername;
|
||||
return this.schemaUsername;
|
||||
}
|
||||
|
||||
public String getSchemaPassword() {
|
||||
return schemaPassword;
|
||||
return this.schemaPassword;
|
||||
}
|
||||
|
||||
public String getTimezoneId() {
|
||||
return timezoneId;
|
||||
return this.timezoneId;
|
||||
}
|
||||
|
||||
public boolean isAutoUpdateEnabled() {
|
||||
|
||||
+28
-24
@@ -20,7 +20,7 @@ import org.mifosplatform.infrastructure.core.serialization.ToApiJsonSerializer;
|
||||
import org.mifosplatform.infrastructure.core.service.ThreadLocalContextUtil;
|
||||
import org.mifosplatform.infrastructure.security.data.PlatformRequestLog;
|
||||
import org.mifosplatform.infrastructure.security.exception.InvalidTenantIdentiferException;
|
||||
import org.mifosplatform.infrastructure.security.service.TenantDetailsService;
|
||||
import org.mifosplatform.infrastructure.security.service.BasicAuthTenantDetailsService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -28,47 +28,51 @@ import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.web.AuthenticationEntryPoint;
|
||||
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* A customised version of spring security's {@link BasicAuthenticationFilter}.
|
||||
*
|
||||
*
|
||||
* This filter is responsible for extracting multi-tenant and basic auth
|
||||
* credentials from the request and checking that the details provided are
|
||||
* valid.
|
||||
*
|
||||
*
|
||||
* If multi-tenant and basic auth credentials are valid, the details of the
|
||||
* tenant are stored in {@link MifosPlatformTenant} and stored in a
|
||||
* {@link ThreadLocal} variable for this request using
|
||||
* {@link ThreadLocalContextUtil}.
|
||||
*
|
||||
*
|
||||
* If multi-tenant and basic auth credentials are invalid, a http error response
|
||||
* is returned.
|
||||
*/
|
||||
@Service(value = "basicAuthenticationProcessingFilter")
|
||||
public class TenantAwareBasicAuthenticationFilter extends BasicAuthenticationFilter {
|
||||
|
||||
private final static Logger logger = LoggerFactory.getLogger(TenantAwareBasicAuthenticationFilter.class);
|
||||
|
||||
@Autowired
|
||||
private TenantDetailsService tenantDetailsService;
|
||||
private final BasicAuthTenantDetailsService basicAuthTenantDetailsService;
|
||||
private final ToApiJsonSerializer<PlatformRequestLog> toApiJsonSerializer;
|
||||
|
||||
private final String tenantRequestHeader = "X-Mifos-Platform-TenantId";
|
||||
private final boolean exceptionIfHeaderMissing = true;
|
||||
|
||||
@Autowired
|
||||
private ToApiJsonSerializer<PlatformRequestLog> toApiJsonSerializer;
|
||||
|
||||
private String tenantRequestHeader = "X-Mifos-Platform-TenantId";
|
||||
private boolean exceptionIfHeaderMissing = true;
|
||||
|
||||
public TenantAwareBasicAuthenticationFilter(final AuthenticationManager authenticationManager,
|
||||
final AuthenticationEntryPoint authenticationEntryPoint) {
|
||||
final AuthenticationEntryPoint authenticationEntryPoint,
|
||||
final BasicAuthTenantDetailsService basicAuthTenantDetailsService,
|
||||
final ToApiJsonSerializer<PlatformRequestLog> toApiJsonSerializer) {
|
||||
super(authenticationManager, authenticationEntryPoint);
|
||||
this.basicAuthTenantDetailsService = basicAuthTenantDetailsService;
|
||||
this.toApiJsonSerializer = toApiJsonSerializer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
|
||||
public void doFilter(final ServletRequest req, final ServletResponse res, final FilterChain chain) throws IOException, ServletException {
|
||||
|
||||
HttpServletRequest request = (HttpServletRequest) req;
|
||||
HttpServletResponse response = (HttpServletResponse) res;
|
||||
final HttpServletRequest request = (HttpServletRequest) req;
|
||||
final HttpServletResponse response = (HttpServletResponse) res;
|
||||
|
||||
StopWatch task = new StopWatch();
|
||||
final StopWatch task = new StopWatch();
|
||||
task.start();
|
||||
|
||||
try {
|
||||
@@ -78,23 +82,23 @@ public class TenantAwareBasicAuthenticationFilter extends BasicAuthenticationFil
|
||||
// in different origin (domain name)
|
||||
} else {
|
||||
|
||||
String tenantId = request.getHeader(tenantRequestHeader);
|
||||
if (org.apache.commons.lang.StringUtils.isBlank(tenantId)) {
|
||||
tenantId = request.getParameter("tenantIdentifier");
|
||||
String tenantIdentifier = request.getHeader(this.tenantRequestHeader);
|
||||
if (org.apache.commons.lang.StringUtils.isBlank(tenantIdentifier)) {
|
||||
tenantIdentifier = request.getParameter("tenantIdentifier");
|
||||
}
|
||||
|
||||
if (tenantId == null && exceptionIfHeaderMissing) { throw new InvalidTenantIdentiferException(
|
||||
"No tenant identifier found: Add request header of '" + tenantRequestHeader
|
||||
if (tenantIdentifier == null && this.exceptionIfHeaderMissing) { throw new InvalidTenantIdentiferException(
|
||||
"No tenant identifier found: Add request header of '" + this.tenantRequestHeader
|
||||
+ "' or add the parameter 'tenantIdentifier' to query string of request URL."); }
|
||||
|
||||
// check tenants database for tenantId
|
||||
final MifosPlatformTenant tenant = this.tenantDetailsService.loadTenantById(tenantId);
|
||||
final MifosPlatformTenant tenant = this.basicAuthTenantDetailsService.loadTenantById(tenantIdentifier);
|
||||
|
||||
ThreadLocalContextUtil.setTenant(tenant);
|
||||
}
|
||||
|
||||
super.doFilter(req, res, chain);
|
||||
} catch (InvalidTenantIdentiferException e) {
|
||||
} catch (final InvalidTenantIdentiferException e) {
|
||||
// deal with exception at low level
|
||||
SecurityContextHolder.getContext().setAuthentication(null);
|
||||
|
||||
@@ -103,7 +107,7 @@ public class TenantAwareBasicAuthenticationFilter extends BasicAuthenticationFil
|
||||
} finally {
|
||||
task.stop();
|
||||
final PlatformRequestLog log = PlatformRequestLog.from(task, request);
|
||||
logger.info(toApiJsonSerializer.serialize(log));
|
||||
logger.info(this.toApiJsonSerializer.serialize(log));
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.infrastructure.security.service;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.domain.MifosPlatformTenant;
|
||||
|
||||
public interface BasicAuthTenantDetailsService {
|
||||
|
||||
MifosPlatformTenant loadTenantById(String tenantId);
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
package org.mifosplatform.infrastructure.security.service;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.domain.MifosPlatformTenant;
|
||||
import org.mifosplatform.infrastructure.security.exception.InvalidTenantIdentiferException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* A JDBC implementation of {@link BasicAuthTenantDetailsService} for loading a
|
||||
* tenants details by a <code>tenantIdentifier</code>.
|
||||
*/
|
||||
@Service
|
||||
public class BasicAuthTenantDetailsServiceJdbc implements BasicAuthTenantDetailsService {
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
@Autowired
|
||||
public BasicAuthTenantDetailsServiceJdbc(@Qualifier("tenantDataSourceJndi") final DataSource dataSource) {
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
private static final class TenantMapper implements RowMapper<MifosPlatformTenant> {
|
||||
|
||||
private final StringBuilder sqlBuilder = new StringBuilder(
|
||||
"id, name,identifier, schema_name as schemaName, schema_server as schemaServer, schema_server_port as schemaServerPort, auto_update as autoUpdate, ")//
|
||||
.append(" schema_username as schemaUsername, schema_password as schemaPassword , timezone_id as timezoneId ")//
|
||||
.append(" from tenants t");//
|
||||
|
||||
public String schema() {
|
||||
return this.sqlBuilder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MifosPlatformTenant mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||
|
||||
final Long id = rs.getLong("id");
|
||||
final String tenantIdentifier = rs.getString("identifier");
|
||||
final String name = rs.getString("name");
|
||||
final String schemaName = rs.getString("schemaName");
|
||||
final String schemaServer = rs.getString("schemaServer");
|
||||
final String schemaServerPort = rs.getString("schemaServerPort");
|
||||
final String schemaUsername = rs.getString("schemaUsername");
|
||||
final String schemaPassword = rs.getString("schemaPassword");
|
||||
final String timezoneId = rs.getString("timezoneId");
|
||||
final boolean autoUpdateEnabled = rs.getBoolean("autoUpdate");
|
||||
|
||||
return new MifosPlatformTenant(id, tenantIdentifier, name, schemaName, schemaServer, schemaServerPort, schemaUsername,
|
||||
schemaPassword, timezoneId, autoUpdateEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "tenantsById")
|
||||
public MifosPlatformTenant loadTenantById(final String tenantIdentifier) {
|
||||
|
||||
try {
|
||||
final TenantMapper rm = new TenantMapper();
|
||||
final String sql = "select " + rm.schema() + " where t.identifier like ?";
|
||||
|
||||
return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { tenantIdentifier });
|
||||
} catch (final EmptyResultDataAccessException e) {
|
||||
throw new InvalidTenantIdentiferException("The tenant identifier: " + tenantIdentifier + " is not valid.");
|
||||
}
|
||||
}
|
||||
}
|
||||
+19
-19
@@ -37,28 +37,28 @@ public class JdbcTenantDetailsService implements TenantDetailsService {
|
||||
|
||||
private static final class TenantMapper implements RowMapper<MifosPlatformTenant> {
|
||||
|
||||
private StringBuilder sqlBuilder = new StringBuilder(
|
||||
private final StringBuilder sqlBuilder = new StringBuilder(
|
||||
"id, name,identifier, schema_name as schemaName, schema_server as schemaServer, schema_server_port as schemaServerPort, auto_update as autoUpdate, ")//
|
||||
.append(" schema_username as schemaUsername, schema_password as schemaPassword , timezone_id as timezoneId ")//
|
||||
.append(" from tenants t");//
|
||||
|
||||
public String schema() {
|
||||
return sqlBuilder.toString();
|
||||
return this.sqlBuilder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MifosPlatformTenant mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||
|
||||
Long id = rs.getLong("id");
|
||||
String tenantIdentifier = rs.getString("identifier");
|
||||
String name = rs.getString("name");
|
||||
String schemaName = rs.getString("schemaName");
|
||||
String schemaServer = rs.getString("schemaServer");
|
||||
String schemaServerPort = rs.getString("schemaServerPort");
|
||||
String schemaUsername = rs.getString("schemaUsername");
|
||||
String schemaPassword = rs.getString("schemaPassword");
|
||||
String timezoneId = rs.getString("timezoneId");
|
||||
boolean autoUpdateEnabled = rs.getBoolean("autoUpdate");
|
||||
final Long id = rs.getLong("id");
|
||||
final String tenantIdentifier = rs.getString("identifier");
|
||||
final String name = rs.getString("name");
|
||||
final String schemaName = rs.getString("schemaName");
|
||||
final String schemaServer = rs.getString("schemaServer");
|
||||
final String schemaServerPort = rs.getString("schemaServerPort");
|
||||
final String schemaUsername = rs.getString("schemaUsername");
|
||||
final String schemaPassword = rs.getString("schemaPassword");
|
||||
final String timezoneId = rs.getString("timezoneId");
|
||||
final boolean autoUpdateEnabled = rs.getBoolean("autoUpdate");
|
||||
|
||||
return new MifosPlatformTenant(id, tenantIdentifier,name, schemaName, schemaServer, schemaServerPort, schemaUsername, schemaPassword,
|
||||
timezoneId, autoUpdateEnabled);
|
||||
@@ -66,25 +66,25 @@ public class JdbcTenantDetailsService implements TenantDetailsService {
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "tenantsById", key = "#tenantIdentifier")
|
||||
@Cacheable(value = "tenantsById")
|
||||
public MifosPlatformTenant loadTenantById(final String tenantIdentifier) {
|
||||
|
||||
try {
|
||||
TenantMapper rm = new TenantMapper();
|
||||
String sql = "select " + rm.schema() + " where t.identifier like ?";
|
||||
final TenantMapper rm = new TenantMapper();
|
||||
final String sql = "select " + rm.schema() + " where t.identifier like ?";
|
||||
|
||||
return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { tenantIdentifier });
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
} catch (final EmptyResultDataAccessException e) {
|
||||
throw new InvalidTenantIdentiferException("The tenant identifier: " + tenantIdentifier + " is not valid.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<MifosPlatformTenant> findAllTenants() {
|
||||
TenantMapper rm = new TenantMapper();
|
||||
String sql = "select " + rm.schema();
|
||||
final TenantMapper rm = new TenantMapper();
|
||||
final String sql = "select " + rm.schema();
|
||||
|
||||
List<MifosPlatformTenant> mifosPlatformTenants = jdbcTemplate.query(sql, rm, new Object[] {});
|
||||
final List<MifosPlatformTenant> mifosPlatformTenants = this.jdbcTemplate.query(sql, rm, new Object[] {});
|
||||
return mifosPlatformTenants;
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -14,5 +14,4 @@ public interface TenantDetailsService {
|
||||
MifosPlatformTenant loadTenantById(String tenantId);
|
||||
|
||||
List<MifosPlatformTenant> findAllTenants();
|
||||
|
||||
}
|
||||
}
|
||||
+11
-11
@@ -53,7 +53,7 @@ public class OfficesApiResource {
|
||||
private final OfficeReadPlatformService readPlatformService;
|
||||
private final DefaultToApiJsonSerializer<OfficeData> toApiJsonSerializer;
|
||||
private final ApiRequestParameterHelper apiRequestParameterHelper;
|
||||
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
|
||||
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
|
||||
|
||||
@Autowired
|
||||
public OfficesApiResource(final PlatformSecurityContext context, final OfficeReadPlatformService readPlatformService,
|
||||
@@ -71,12 +71,12 @@ public class OfficesApiResource {
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveOffices(@Context final UriInfo uriInfo) {
|
||||
|
||||
context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions);
|
||||
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
|
||||
|
||||
final Collection<OfficeData> offices = this.readPlatformService.retrieveAllOffices();
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.toApiJsonSerializer.serialize(settings, offices, RESPONSE_DATA_PARAMETERS);
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.toApiJsonSerializer.serialize(settings, offices, this.RESPONSE_DATA_PARAMETERS);
|
||||
}
|
||||
|
||||
@GET
|
||||
@@ -85,15 +85,15 @@ public class OfficesApiResource {
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retrieveOfficeTemplate(@Context final UriInfo uriInfo) {
|
||||
|
||||
context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions);
|
||||
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
|
||||
|
||||
OfficeData office = this.readPlatformService.retrieveNewOfficeTemplate();
|
||||
|
||||
final Collection<OfficeData> allowedParents = this.readPlatformService.retrieveAllOfficesForDropdown();
|
||||
office = OfficeData.appendedTemplate(office, allowedParents);
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.toApiJsonSerializer.serialize(settings, office, RESPONSE_DATA_PARAMETERS);
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
return this.toApiJsonSerializer.serialize(settings, office, this.RESPONSE_DATA_PARAMETERS);
|
||||
}
|
||||
|
||||
@POST
|
||||
@@ -117,17 +117,17 @@ public class OfficesApiResource {
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
public String retreiveOffice(@PathParam("officeId") final Long officeId, @Context final UriInfo uriInfo) {
|
||||
|
||||
context.authenticatedUser().validateHasReadPermission(resourceNameForPermissions);
|
||||
this.context.authenticatedUser().validateHasReadPermission(this.resourceNameForPermissions);
|
||||
|
||||
final ApiRequestJsonSerializationSettings settings = apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
|
||||
|
||||
OfficeData office = this.readPlatformService.retrieveOffice(officeId);
|
||||
if (settings.isTemplate()) {
|
||||
Collection<OfficeData> allowedParents = this.readPlatformService.retrieveAllowedParents(officeId);
|
||||
final Collection<OfficeData> allowedParents = this.readPlatformService.retrieveAllowedParents(officeId);
|
||||
office = OfficeData.appendedTemplate(office, allowedParents);
|
||||
}
|
||||
|
||||
return this.toApiJsonSerializer.serialize(settings, office, RESPONSE_DATA_PARAMETERS);
|
||||
return this.toApiJsonSerializer.serialize(settings, office, this.RESPONSE_DATA_PARAMETERS);
|
||||
}
|
||||
|
||||
@PUT
|
||||
|
||||
+3
@@ -7,11 +7,14 @@ package org.mifosplatform.organisation.office.service;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.domain.MifosPlatformTenant;
|
||||
import org.mifosplatform.organisation.office.data.OfficeData;
|
||||
import org.mifosplatform.organisation.office.data.OfficeTransactionData;
|
||||
|
||||
public interface OfficeReadPlatformService {
|
||||
|
||||
MifosPlatformTenant loadTenantById(String tenantIdentifier);
|
||||
|
||||
Collection<OfficeData> retrieveAllOffices();
|
||||
|
||||
Collection<OfficeData> retrieveAllOfficesForDropdown();
|
||||
|
||||
+93
-41
@@ -11,9 +11,13 @@ import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
|
||||
import org.mifosplatform.infrastructure.core.domain.MifosPlatformTenant;
|
||||
import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
|
||||
import org.mifosplatform.infrastructure.security.exception.InvalidTenantIdentiferException;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.organisation.monetary.data.CurrencyData;
|
||||
import org.mifosplatform.organisation.monetary.service.CurrencyReadPlatformService;
|
||||
@@ -22,6 +26,7 @@ import org.mifosplatform.organisation.office.data.OfficeTransactionData;
|
||||
import org.mifosplatform.organisation.office.exception.OfficeNotFoundException;
|
||||
import org.mifosplatform.useradministration.domain.AppUser;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
@@ -32,16 +37,19 @@ import org.springframework.stereotype.Service;
|
||||
public class OfficeReadPlatformServiceImpl implements OfficeReadPlatformService {
|
||||
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
private final JdbcTemplate tenantsJdbcTemplate;
|
||||
private final PlatformSecurityContext context;
|
||||
private final CurrencyReadPlatformService currencyReadPlatformService;
|
||||
private final static String nameDecoratedBaseOnHierarchy = "concat(substring('........................................', 1, ((LENGTH(o.hierarchy) - LENGTH(REPLACE(o.hierarchy, '.', '')) - 1) * 4)), o.name)";
|
||||
|
||||
@Autowired
|
||||
public OfficeReadPlatformServiceImpl(final PlatformSecurityContext context,
|
||||
final CurrencyReadPlatformService currencyReadPlatformService, final RoutingDataSource dataSource) {
|
||||
final CurrencyReadPlatformService currencyReadPlatformService, final RoutingDataSource dataSource,
|
||||
@Qualifier("tenantDataSourceJndi") final DataSource tenantsJndiDataSource) {
|
||||
this.context = context;
|
||||
this.currencyReadPlatformService = currencyReadPlatformService;
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
this.tenantsJdbcTemplate = new JdbcTemplate(tenantsJndiDataSource);
|
||||
}
|
||||
|
||||
private static final class OfficeMapper implements RowMapper<OfficeData> {
|
||||
@@ -101,25 +109,25 @@ public class OfficeReadPlatformServiceImpl implements OfficeReadPlatformService
|
||||
@Override
|
||||
public OfficeTransactionData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||
|
||||
Long id = rs.getLong("id");
|
||||
LocalDate transactionDate = JdbcSupport.getLocalDate(rs, "transactionDate");
|
||||
Long fromOfficeId = JdbcSupport.getLong(rs, "fromOfficeId");
|
||||
String fromOfficeName = rs.getString("fromOfficeName");
|
||||
Long toOfficeId = JdbcSupport.getLong(rs, "toOfficeId");
|
||||
String toOfficeName = rs.getString("toOfficeName");
|
||||
final Long id = rs.getLong("id");
|
||||
final LocalDate transactionDate = JdbcSupport.getLocalDate(rs, "transactionDate");
|
||||
final Long fromOfficeId = JdbcSupport.getLong(rs, "fromOfficeId");
|
||||
final String fromOfficeName = rs.getString("fromOfficeName");
|
||||
final Long toOfficeId = JdbcSupport.getLong(rs, "toOfficeId");
|
||||
final String toOfficeName = rs.getString("toOfficeName");
|
||||
|
||||
String currencyCode = rs.getString("currencyCode");
|
||||
String currencyName = rs.getString("currencyName");
|
||||
String currencyNameCode = rs.getString("currencyNameCode");
|
||||
String currencyDisplaySymbol = rs.getString("currencyDisplaySymbol");
|
||||
Integer currencyDigits = JdbcSupport.getInteger(rs, "currencyDigits");
|
||||
Integer inMultiplesOf = JdbcSupport.getInteger(rs, "inMultiplesOf");
|
||||
final String currencyCode = rs.getString("currencyCode");
|
||||
final String currencyName = rs.getString("currencyName");
|
||||
final String currencyNameCode = rs.getString("currencyNameCode");
|
||||
final String currencyDisplaySymbol = rs.getString("currencyDisplaySymbol");
|
||||
final Integer currencyDigits = JdbcSupport.getInteger(rs, "currencyDigits");
|
||||
final Integer inMultiplesOf = JdbcSupport.getInteger(rs, "inMultiplesOf");
|
||||
|
||||
CurrencyData currencyData = new CurrencyData(currencyCode, currencyName, currencyDigits, inMultiplesOf,
|
||||
currencyDisplaySymbol, currencyNameCode);
|
||||
final CurrencyData currencyData = new CurrencyData(currencyCode, currencyName, currencyDigits, inMultiplesOf, currencyDisplaySymbol,
|
||||
currencyNameCode);
|
||||
|
||||
BigDecimal transactionAmount = rs.getBigDecimal("transactionAmount");
|
||||
String description = rs.getString("description");
|
||||
final BigDecimal transactionAmount = rs.getBigDecimal("transactionAmount");
|
||||
final String description = rs.getString("description");
|
||||
|
||||
return OfficeTransactionData.instance(id, transactionDate, fromOfficeId, fromOfficeName, toOfficeId, toOfficeName,
|
||||
currencyData, transactionAmount, description);
|
||||
@@ -130,13 +138,13 @@ public class OfficeReadPlatformServiceImpl implements OfficeReadPlatformService
|
||||
@Cacheable(value = "offices", key = "T(org.mifosplatform.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat(#root.target.context.authenticatedUser().getOffice().getHierarchy()+'of')")
|
||||
public Collection<OfficeData> retrieveAllOffices() {
|
||||
|
||||
AppUser currentUser = context.authenticatedUser();
|
||||
final AppUser currentUser = this.context.authenticatedUser();
|
||||
|
||||
String hierarchy = currentUser.getOffice().getHierarchy();
|
||||
String hierarchySearchString = hierarchy + "%";
|
||||
final String hierarchy = currentUser.getOffice().getHierarchy();
|
||||
final String hierarchySearchString = hierarchy + "%";
|
||||
|
||||
OfficeMapper rm = new OfficeMapper();
|
||||
String sql = "select " + rm.officeSchema() + "where o.hierarchy like ? order by o.hierarchy";
|
||||
final OfficeMapper rm = new OfficeMapper();
|
||||
final String sql = "select " + rm.officeSchema() + "where o.hierarchy like ? order by o.hierarchy";
|
||||
|
||||
return this.jdbcTemplate.query(sql, rm, new Object[] { hierarchySearchString });
|
||||
}
|
||||
@@ -144,7 +152,7 @@ public class OfficeReadPlatformServiceImpl implements OfficeReadPlatformService
|
||||
@Override
|
||||
@Cacheable(value = "officesForDropdown", key = "T(org.mifosplatform.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat(#root.target.context.authenticatedUser().getOffice().getHierarchy()+'ofd')")
|
||||
public Collection<OfficeData> retrieveAllOfficesForDropdown() {
|
||||
final AppUser currentUser = context.authenticatedUser();
|
||||
final AppUser currentUser = this.context.authenticatedUser();
|
||||
|
||||
final String hierarchy = currentUser.getOffice().getHierarchy();
|
||||
final String hierarchySearchString = hierarchy + "%";
|
||||
@@ -160,15 +168,15 @@ public class OfficeReadPlatformServiceImpl implements OfficeReadPlatformService
|
||||
public OfficeData retrieveOffice(final Long officeId) {
|
||||
|
||||
try {
|
||||
context.authenticatedUser();
|
||||
this.context.authenticatedUser();
|
||||
|
||||
OfficeMapper rm = new OfficeMapper();
|
||||
String sql = "select " + rm.officeSchema() + " where o.id = ?";
|
||||
final OfficeMapper rm = new OfficeMapper();
|
||||
final String sql = "select " + rm.officeSchema() + " where o.id = ?";
|
||||
|
||||
OfficeData selectedOffice = this.jdbcTemplate.queryForObject(sql, rm, new Object[] { officeId });
|
||||
final OfficeData selectedOffice = this.jdbcTemplate.queryForObject(sql, rm, new Object[] { officeId });
|
||||
|
||||
return selectedOffice;
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
} catch (final EmptyResultDataAccessException e) {
|
||||
throw new OfficeNotFoundException(officeId);
|
||||
}
|
||||
}
|
||||
@@ -176,7 +184,7 @@ public class OfficeReadPlatformServiceImpl implements OfficeReadPlatformService
|
||||
@Override
|
||||
public OfficeData retrieveNewOfficeTemplate() {
|
||||
|
||||
context.authenticatedUser();
|
||||
this.context.authenticatedUser();
|
||||
|
||||
return OfficeData.template(null, new LocalDate());
|
||||
}
|
||||
@@ -184,13 +192,13 @@ public class OfficeReadPlatformServiceImpl implements OfficeReadPlatformService
|
||||
@Override
|
||||
public Collection<OfficeData> retrieveAllowedParents(final Long officeId) {
|
||||
|
||||
context.authenticatedUser();
|
||||
Collection<OfficeData> filterParentLookups = new ArrayList<OfficeData>();
|
||||
this.context.authenticatedUser();
|
||||
final Collection<OfficeData> filterParentLookups = new ArrayList<OfficeData>();
|
||||
|
||||
if (isNotHeadOffice(officeId)) {
|
||||
Collection<OfficeData> parentLookups = retrieveAllOfficesForDropdown();
|
||||
final Collection<OfficeData> parentLookups = retrieveAllOfficesForDropdown();
|
||||
|
||||
for (OfficeData office : parentLookups) {
|
||||
for (final OfficeData office : parentLookups) {
|
||||
if (!office.hasIdentifyOf(officeId)) {
|
||||
filterParentLookups.add(office);
|
||||
}
|
||||
@@ -207,13 +215,13 @@ public class OfficeReadPlatformServiceImpl implements OfficeReadPlatformService
|
||||
@Override
|
||||
public Collection<OfficeTransactionData> retrieveAllOfficeTransactions() {
|
||||
|
||||
AppUser currentUser = context.authenticatedUser();
|
||||
final AppUser currentUser = this.context.authenticatedUser();
|
||||
|
||||
String hierarchy = currentUser.getOffice().getHierarchy();
|
||||
String hierarchySearchString = hierarchy + "%";
|
||||
final String hierarchy = currentUser.getOffice().getHierarchy();
|
||||
final String hierarchySearchString = hierarchy + "%";
|
||||
|
||||
OfficeTransactionMapper rm = new OfficeTransactionMapper();
|
||||
String sql = "select " + rm.schema()
|
||||
final OfficeTransactionMapper rm = new OfficeTransactionMapper();
|
||||
final String sql = "select " + rm.schema()
|
||||
+ " where (fromoff.hierarchy like ? or tooff.hierarchy like ?) order by ot.transaction_date, ot.id";
|
||||
|
||||
return this.jdbcTemplate.query(sql, rm, new Object[] { hierarchySearchString, hierarchySearchString });
|
||||
@@ -221,15 +229,59 @@ public class OfficeReadPlatformServiceImpl implements OfficeReadPlatformService
|
||||
|
||||
@Override
|
||||
public OfficeTransactionData retrieveNewOfficeTransactionDetails() {
|
||||
context.authenticatedUser();
|
||||
this.context.authenticatedUser();
|
||||
|
||||
final Collection<OfficeData> parentLookups = retrieveAllOfficesForDropdown();
|
||||
final Collection<CurrencyData> currencyOptions = currencyReadPlatformService.retrieveAllowedCurrencies();
|
||||
final Collection<CurrencyData> currencyOptions = this.currencyReadPlatformService.retrieveAllowedCurrencies();
|
||||
|
||||
return OfficeTransactionData.template(new LocalDate(), parentLookups, currencyOptions);
|
||||
}
|
||||
|
||||
|
||||
public PlatformSecurityContext getContext() {
|
||||
return this.context;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Cacheable(value = "tenantsById", key="#tenantIdentifier")
|
||||
public MifosPlatformTenant loadTenantById(final String tenantIdentifier) {
|
||||
|
||||
try {
|
||||
final TenantMapper rm = new TenantMapper();
|
||||
final String sql = "select " + rm.schema() + " where t.identifier like ?";
|
||||
|
||||
return this.tenantsJdbcTemplate.queryForObject(sql, rm, new Object[] { tenantIdentifier });
|
||||
} catch (final EmptyResultDataAccessException e) {
|
||||
throw new InvalidTenantIdentiferException("The tenant identifier: " + tenantIdentifier + " is not valid.");
|
||||
}
|
||||
}
|
||||
|
||||
private static final class TenantMapper implements RowMapper<MifosPlatformTenant> {
|
||||
|
||||
private final StringBuilder sqlBuilder = new StringBuilder(
|
||||
"id, name,identifier, schema_name as schemaName, schema_server as schemaServer, schema_server_port as schemaServerPort, auto_update as autoUpdate, ")//
|
||||
.append(" schema_username as schemaUsername, schema_password as schemaPassword , timezone_id as timezoneId ")//
|
||||
.append(" from tenants t");//
|
||||
|
||||
public String schema() {
|
||||
return this.sqlBuilder.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MifosPlatformTenant mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException {
|
||||
|
||||
final Long id = rs.getLong("id");
|
||||
final String tenantIdentifier = rs.getString("identifier");
|
||||
final String name = rs.getString("name");
|
||||
final String schemaName = rs.getString("schemaName");
|
||||
final String schemaServer = rs.getString("schemaServer");
|
||||
final String schemaServerPort = rs.getString("schemaServerPort");
|
||||
final String schemaUsername = rs.getString("schemaUsername");
|
||||
final String schemaPassword = rs.getString("schemaPassword");
|
||||
final String timezoneId = rs.getString("timezoneId");
|
||||
final boolean autoUpdateEnabled = rs.getBoolean("autoUpdate");
|
||||
|
||||
return new MifosPlatformTenant(id, tenantIdentifier, name, schemaName, schemaServer, schemaServerPort, schemaUsername,
|
||||
schemaPassword, timezoneId, autoUpdateEnabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-4
@@ -5,7 +5,6 @@
|
||||
*/
|
||||
package org.mifosplatform.useradministration.domain;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
@@ -26,7 +25,7 @@ import org.mifosplatform.useradministration.data.RoleData;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_role", uniqueConstraints = { @UniqueConstraint(columnNames = { "name" }, name = "unq_name")})
|
||||
@Table(name = "m_role", uniqueConstraints = { @UniqueConstraint(columnNames = { "name" }, name = "unq_name") })
|
||||
public class Role extends AbstractPersistable<Long> {
|
||||
|
||||
@Column(name = "name", unique = true, nullable = false, length = 100)
|
||||
@@ -100,7 +99,7 @@ public class Role extends AbstractPersistable<Long> {
|
||||
|
||||
public boolean hasPermissionTo(final String permissionCode) {
|
||||
boolean match = false;
|
||||
for (Permission permission : this.permissions) {
|
||||
for (final Permission permission : this.permissions) {
|
||||
if (permission.hasCode(permissionCode)) {
|
||||
match = true;
|
||||
break;
|
||||
@@ -110,6 +109,6 @@ public class Role extends AbstractPersistable<Long> {
|
||||
}
|
||||
|
||||
public RoleData toData() {
|
||||
return new RoleData(this.getId(), this.name, this.description);
|
||||
return new RoleData(getId(), this.name, this.description);
|
||||
}
|
||||
}
|
||||
@@ -24,8 +24,6 @@
|
||||
|
||||
<tx:annotation-driven />
|
||||
|
||||
<cache:annotation-driven />
|
||||
|
||||
<context:component-scan base-package="org.mifosplatform.accounting.*,
|
||||
org.mifosplatform.commands.handler.*,
|
||||
org.mifosplatform.commands.service.*,
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
|
||||
http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">
|
||||
|
||||
<bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"
|
||||
p:cacheManager-ref="ehcache" />
|
||||
<bean id="ehcacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager"
|
||||
p:cacheManager-ref="ehcacheInstance" />
|
||||
|
||||
<bean id="ehcache"
|
||||
<bean id="ehcacheInstance"
|
||||
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean"
|
||||
p:configLocation="classpath:/META-INF/spring/ehcache.xml" p:shared="true" />
|
||||
|
||||
|
||||
@@ -29,11 +29,12 @@
|
||||
<beans:property name="realmName" value="Mifos Platform API" />
|
||||
</beans:bean>
|
||||
|
||||
<!--
|
||||
<beans:bean id="basicAuthenticationProcessingFilter" class="org.mifosplatform.infrastructure.security.filter.TenantAwareBasicAuthenticationFilter" depends-on="cacheManager">
|
||||
<beans:constructor-arg ref="authenticationManager" />
|
||||
<beans:constructor-arg ref="basicAuthenticationEntryPoint" />
|
||||
</beans:bean>
|
||||
|
||||
-->
|
||||
<beans:bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder">
|
||||
<beans:constructor-arg value="256"/>
|
||||
</beans:bean>
|
||||
|
||||
Reference in New Issue
Block a user