diff --git a/lightadmin-core/pom.xml b/lightadmin-core/pom.xml index 9aa8a28c..a9ca8391 100644 --- a/lightadmin-core/pom.xml +++ b/lightadmin-core/pom.xml @@ -7,8 +7,7 @@ org.lightadmin lightadmin jar - - 1.2.0.BUILD-SNAPSHOT + 1.3.1.BUILD-SNAPSHOT LightAdmin Pluggable data management solution for Java web applications developed in a "Rapid" manner @@ -92,10 +91,10 @@ UTF-8 UTF-8 - 1.7 - 1.7 + 1.8 + 1.8 - 1.1.2.RELEASE + Brussels-SR6 4.0 4.2 @@ -502,6 +501,19 @@ + + vantage-distribution + + + third-party-snapshots + http://maven2.vantage.com:8080/repo/content/repositories/third-party-snapshots + + + third-party + http://maven2.vantage.com:8080/repo/content/repositories/third-party + + + oss-distribution diff --git a/lightadmin-core/src/main/java/org/lightadmin/core/config/LightAdminConfiguration.java b/lightadmin-core/src/main/java/org/lightadmin/core/config/LightAdminConfiguration.java index 3f7e6d28..1d76a3a9 100644 --- a/lightadmin-core/src/main/java/org/lightadmin/core/config/LightAdminConfiguration.java +++ b/lightadmin-core/src/main/java/org/lightadmin/core/config/LightAdminConfiguration.java @@ -1,45 +1,47 @@ -/* - * Copyright 2012-2014 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.lightadmin.core.config; - -import java.io.File; -import java.net.URI; - -public interface LightAdminConfiguration { - - String getBasePackage(); - - String getApplicationBaseUrl(); - - String getApplicationUrl(String path); - - URI getApplicationRestBaseUrl(); - - boolean isSecurityEnabled(); - - boolean isDemoMode(); - - String getSecurityLogoutUrl(); - - String getBackToSiteUrl(); - - String getHelpUrl(); - - File getFileStorageDirectory(); - - boolean isFileStreamingEnabled(); - +/* + * Copyright 2012-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.lightadmin.core.config; + +import java.io.File; +import java.net.URI; + +public interface LightAdminConfiguration { + + String getBasePackage(); + + String getApplicationBaseUrl(); + + String getApplicationUrl(String path); + + URI getApplicationRestBaseUrl(); + + String getApplicationRestBasePath(); + + boolean isSecurityEnabled(); + + boolean isDemoMode(); + + String getSecurityLogoutUrl(); + + String getBackToSiteUrl(); + + String getHelpUrl(); + + File getFileStorageDirectory(); + + boolean isFileStreamingEnabled(); + } \ No newline at end of file diff --git a/lightadmin-core/src/main/java/org/lightadmin/core/config/StandardLightAdminConfiguration.java b/lightadmin-core/src/main/java/org/lightadmin/core/config/StandardLightAdminConfiguration.java index f00624a3..6359824a 100644 --- a/lightadmin-core/src/main/java/org/lightadmin/core/config/StandardLightAdminConfiguration.java +++ b/lightadmin-core/src/main/java/org/lightadmin/core/config/StandardLightAdminConfiguration.java @@ -1,139 +1,144 @@ -/* - * Copyright 2012-2014 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.lightadmin.core.config; - -import org.apache.commons.lang3.BooleanUtils; -import org.springframework.web.util.UriComponentsBuilder; - -import javax.servlet.ServletContext; -import java.io.File; -import java.net.URI; - -import static org.apache.commons.io.FileUtils.getFile; -import static org.apache.commons.lang3.StringUtils.defaultIfBlank; -import static org.apache.commons.lang3.StringUtils.isBlank; -import static org.lightadmin.core.util.LightAdminConfigurationUtils.*; - -public class StandardLightAdminConfiguration implements LightAdminConfiguration { - - private final String applicationBaseUrl; - private final String applicationBaseNoEndSeparator; - private final boolean securityEnabled; - private final String securityLogoutUrl; - private final String backToSiteUrl; - private final String helpUrl; - private final File fileStorageDirectory; - private final boolean fileStreaming; - private final String basePackage; - private final boolean demoMode; - - public StandardLightAdminConfiguration(ServletContext servletContext) { - this.basePackage = servletContext.getInitParameter(LIGHT_ADMINISTRATION_BASE_PACKAGE); - - this.applicationBaseUrl = servletContext.getInitParameter(LIGHT_ADMINISTRATION_BASE_URL); - this.applicationBaseNoEndSeparator = urlWithoutEndSeparator(this.applicationBaseUrl); - this.backToSiteUrl = backToSiteUrl(servletContext); - this.helpUrl = helpUrl(servletContext); - - this.fileStorageDirectory = fileStorageDirectory(servletContext); - this.fileStreaming = BooleanUtils.toBoolean(servletContext.getInitParameter(LIGHT_ADMINISTRATION_FILE_STREAMING)); - - this.demoMode = BooleanUtils.toBoolean(servletContext.getInitParameter(LIGHT_ADMINISTRATION_DEMO_MODE)); - - this.securityEnabled = BooleanUtils.toBoolean(servletContext.getInitParameter(LIGHT_ADMINISTRATION_SECURITY)); - if (securityEnabled) { - this.securityLogoutUrl = servletContext.getContextPath() + this.applicationBaseNoEndSeparator + LIGHT_ADMIN_SECURITY_LOGOUT_URL_DEFAULT; - } else { - this.securityLogoutUrl = servletContext.getContextPath() + defaultIfBlank(servletContext.getInitParameter(LIGHT_ADMINISTRATION_SECURITY_LOGOUT_URL), "#"); - } - } - - @Override - public URI getApplicationRestBaseUrl() { - return UriComponentsBuilder.fromUriString(LIGHT_ADMIN_REST_URL_DEFAULT).build().toUri(); - } - - @Override - public String getBasePackage() { - return this.basePackage; - } - - @Override - public File getFileStorageDirectory() { - return fileStorageDirectory; - } - - @Override - public boolean isFileStreamingEnabled() { - return fileStreaming; - } - - @Override - public String getBackToSiteUrl() { - return backToSiteUrl; - } - - @Override - public String getHelpUrl() { - return helpUrl; - } - - @Override - public String getApplicationBaseUrl() { - return applicationBaseUrl; - } - - @Override - public String getApplicationUrl(String path) { - return applicationBaseNoEndSeparator + path; - } - - @Override - public boolean isSecurityEnabled() { - return securityEnabled; - } - - public boolean isDemoMode() { - return demoMode; - } - - @Override - public String getSecurityLogoutUrl() { - return securityLogoutUrl; - } - - private File fileStorageDirectory(ServletContext servletContext) { - final String fileStoragePath = servletContext.getInitParameter(LIGHT_ADMINISTRATION_FILE_STORAGE_PATH); - - return isBlank(fileStoragePath) ? null : getFile(fileStoragePath); - } - - private String backToSiteUrl(ServletContext servletContext) { - final String backToSiteUrl = servletContext.getInitParameter(LIGHT_ADMINISTRATION_BACK_TO_SITE_URL); - - return isBlank(backToSiteUrl) ? LIGHT_ADMINISTRATION_BACK_TO_SITE_DEFAULT_URL : backToSiteUrl; - } - - private String helpUrl(ServletContext servletContext) { - final String helpUrl = servletContext.getInitParameter(LIGHT_ADMINISTRATION_HELP_URL); - - return isBlank(helpUrl) ? LIGHT_ADMINISTRATION_HELP_DEFAULT_URL : helpUrl; - } - - private String urlWithoutEndSeparator(String url) { - return url.endsWith("/") ? url.substring(0, url.length() - 1) : url; - } +/* + * Copyright 2012-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.lightadmin.core.config; + +import org.apache.commons.lang3.BooleanUtils; +import org.springframework.web.util.UriComponentsBuilder; + +import javax.servlet.ServletContext; +import java.io.File; +import java.net.URI; + +import static org.apache.commons.io.FileUtils.getFile; +import static org.apache.commons.lang3.StringUtils.defaultIfBlank; +import static org.apache.commons.lang3.StringUtils.isBlank; +import static org.lightadmin.core.util.LightAdminConfigurationUtils.*; + +public class StandardLightAdminConfiguration implements LightAdminConfiguration { + + private final String applicationBaseUrl; + private final String applicationBaseNoEndSeparator; + private final boolean securityEnabled; + private final String securityLogoutUrl; + private final String backToSiteUrl; + private final String helpUrl; + private final File fileStorageDirectory; + private final boolean fileStreaming; + private final String basePackage; + private final boolean demoMode; + + public StandardLightAdminConfiguration(ServletContext servletContext) { + this.basePackage = servletContext.getInitParameter(LIGHT_ADMINISTRATION_BASE_PACKAGE); + + this.applicationBaseUrl = servletContext.getInitParameter(LIGHT_ADMINISTRATION_BASE_URL); + this.applicationBaseNoEndSeparator = urlWithoutEndSeparator(this.applicationBaseUrl); + this.backToSiteUrl = backToSiteUrl(servletContext); + this.helpUrl = helpUrl(servletContext); + + this.fileStorageDirectory = fileStorageDirectory(servletContext); + this.fileStreaming = BooleanUtils.toBoolean(servletContext.getInitParameter(LIGHT_ADMINISTRATION_FILE_STREAMING)); + + this.demoMode = BooleanUtils.toBoolean(servletContext.getInitParameter(LIGHT_ADMINISTRATION_DEMO_MODE)); + + this.securityEnabled = BooleanUtils.toBoolean(servletContext.getInitParameter(LIGHT_ADMINISTRATION_SECURITY)); + if (securityEnabled) { + this.securityLogoutUrl = servletContext.getContextPath() + this.applicationBaseNoEndSeparator + LIGHT_ADMIN_SECURITY_LOGOUT_URL_DEFAULT; + } else { + this.securityLogoutUrl = servletContext.getContextPath() + defaultIfBlank(servletContext.getInitParameter(LIGHT_ADMINISTRATION_SECURITY_LOGOUT_URL), "#"); + } + } + + @Override + public URI getApplicationRestBaseUrl() { + return UriComponentsBuilder.fromUriString(LIGHT_ADMIN_REST_URL_DEFAULT).build().toUri(); + } + + @Override + public String getApplicationRestBasePath() { + return LIGHT_ADMIN_REST_URL_DEFAULT; + } + + @Override + public String getBasePackage() { + return this.basePackage; + } + + @Override + public File getFileStorageDirectory() { + return fileStorageDirectory; + } + + @Override + public boolean isFileStreamingEnabled() { + return fileStreaming; + } + + @Override + public String getBackToSiteUrl() { + return backToSiteUrl; + } + + @Override + public String getHelpUrl() { + return helpUrl; + } + + @Override + public String getApplicationBaseUrl() { + return applicationBaseUrl; + } + + @Override + public String getApplicationUrl(String path) { + return applicationBaseNoEndSeparator + path; + } + + @Override + public boolean isSecurityEnabled() { + return securityEnabled; + } + + public boolean isDemoMode() { + return demoMode; + } + + @Override + public String getSecurityLogoutUrl() { + return securityLogoutUrl; + } + + private File fileStorageDirectory(ServletContext servletContext) { + final String fileStoragePath = servletContext.getInitParameter(LIGHT_ADMINISTRATION_FILE_STORAGE_PATH); + + return isBlank(fileStoragePath) ? null : getFile(fileStoragePath); + } + + private String backToSiteUrl(ServletContext servletContext) { + final String backToSiteUrl = servletContext.getInitParameter(LIGHT_ADMINISTRATION_BACK_TO_SITE_URL); + + return isBlank(backToSiteUrl) ? LIGHT_ADMINISTRATION_BACK_TO_SITE_DEFAULT_URL : backToSiteUrl; + } + + private String helpUrl(ServletContext servletContext) { + final String helpUrl = servletContext.getInitParameter(LIGHT_ADMINISTRATION_HELP_URL); + + return isBlank(helpUrl) ? LIGHT_ADMINISTRATION_HELP_DEFAULT_URL : helpUrl; + } + + private String urlWithoutEndSeparator(String url) { + return url.endsWith("/") ? url.substring(0, url.length() - 1) : url; + } } \ No newline at end of file diff --git a/lightadmin-core/src/main/java/org/lightadmin/core/config/bootstrap/JpaMetamodelMappingContextFactoryBean.java b/lightadmin-core/src/main/java/org/lightadmin/core/config/bootstrap/JpaMetamodelMappingContextFactoryBean.java index 82365dd7..eef96bf3 100644 --- a/lightadmin-core/src/main/java/org/lightadmin/core/config/bootstrap/JpaMetamodelMappingContextFactoryBean.java +++ b/lightadmin-core/src/main/java/org/lightadmin/core/config/bootstrap/JpaMetamodelMappingContextFactoryBean.java @@ -1,71 +1,73 @@ -/* - * Copyright 2012-2014 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.lightadmin.core.config.bootstrap; - -import org.springframework.beans.factory.config.AbstractFactoryBean; -import org.springframework.data.jpa.mapping.JpaMetamodelMappingContext; -import org.springframework.util.Assert; - -import javax.persistence.EntityManager; -import javax.persistence.metamodel.ManagedType; -import javax.persistence.metamodel.Metamodel; -import java.util.HashSet; -import java.util.Set; - -public class JpaMetamodelMappingContextFactoryBean extends AbstractFactoryBean { - - private EntityManager entityManager; - - @Override - public Class getObjectType() { - return JpaMetamodelMappingContext.class; - } - - @Override - protected JpaMetamodelMappingContext createInstance() throws Exception { - Metamodel metamodel = entityManager.getMetamodel(); - - Set> managedTypes = metamodel.getManagedTypes(); - Set> entitySources = new HashSet>(managedTypes.size()); - - for (ManagedType type : managedTypes) { - - Class javaType = type.getJavaType(); - - if (javaType != null) { - entitySources.add(javaType); - } - } - - JpaMetamodelMappingContext context = new JpaMetamodelMappingContext(metamodel); - context.setInitialEntitySet(entitySources); - context.initialize(); - - return context; - } - - @Override - public void afterPropertiesSet() throws Exception { - Assert.notNull(entityManager, "EntityManager must not be null!"); - super.afterPropertiesSet(); - } - - @SuppressWarnings("unused") - public void setEntityManager(EntityManager entityManager) { - Assert.notNull(entityManager, "EntityManager must not be null!"); - this.entityManager = entityManager; - } +/* + * Copyright 2012-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.lightadmin.core.config.bootstrap; + +import org.springframework.beans.factory.config.AbstractFactoryBean; +import org.springframework.data.jpa.mapping.JpaMetamodelMappingContext; +import org.springframework.util.Assert; + +import javax.persistence.EntityManager; +import javax.persistence.metamodel.ManagedType; +import javax.persistence.metamodel.Metamodel; +import java.util.HashSet; +import java.util.Set; + +public class JpaMetamodelMappingContextFactoryBean extends AbstractFactoryBean { + + private EntityManager entityManager; + + @Override + public Class getObjectType() { + return JpaMetamodelMappingContext.class; + } + + @Override + protected JpaMetamodelMappingContext createInstance() throws Exception { + Metamodel metamodel = entityManager.getMetamodel(); + + Set> managedTypes = metamodel.getManagedTypes(); + Set> entitySources = new HashSet>(managedTypes.size()); + + for (ManagedType type : managedTypes) { + + Class javaType = type.getJavaType(); + + if (javaType != null) { + entitySources.add(javaType); + } + } + + Set metamodels = new HashSet<>(); + metamodels.add(metamodel); + JpaMetamodelMappingContext context = new JpaMetamodelMappingContext(metamodels); + context.setInitialEntitySet(entitySources); + context.initialize(); + + return context; + } + + @Override + public void afterPropertiesSet() throws Exception { + Assert.notNull(entityManager, "EntityManager must not be null!"); + super.afterPropertiesSet(); + } + + @SuppressWarnings("unused") + public void setEntityManager(EntityManager entityManager) { + Assert.notNull(entityManager, "EntityManager must not be null!"); + this.entityManager = entityManager; + } } \ No newline at end of file diff --git a/lightadmin-core/src/main/java/org/lightadmin/core/config/bootstrap/LightAdminBeanDefinitionRegistryPostProcessor.java b/lightadmin-core/src/main/java/org/lightadmin/core/config/bootstrap/LightAdminBeanDefinitionRegistryPostProcessor.java index 904e84ca..de4673cd 100644 --- a/lightadmin-core/src/main/java/org/lightadmin/core/config/bootstrap/LightAdminBeanDefinitionRegistryPostProcessor.java +++ b/lightadmin-core/src/main/java/org/lightadmin/core/config/bootstrap/LightAdminBeanDefinitionRegistryPostProcessor.java @@ -1,214 +1,215 @@ -/* - * Copyright 2012-2014 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.lightadmin.core.config.bootstrap; - -import org.lightadmin.core.config.bootstrap.parsing.validation.CompositeConfigurationUnitsValidator; -import org.lightadmin.core.config.bootstrap.scanning.AdministrationClassScanner; -import org.lightadmin.core.config.bootstrap.scanning.ClassScanner; -import org.lightadmin.core.config.domain.DomainTypeAdministrationConfigurationFactory; -import org.lightadmin.core.config.domain.GlobalAdministrationConfiguration; -import org.lightadmin.core.config.domain.unit.ConfigurationUnits; -import org.lightadmin.core.persistence.repository.DynamicRepositoryClassFactory; -import org.lightadmin.core.persistence.repository.JavassistDynamicJpaRepositoryClassFactory; -import org.lightadmin.core.util.DynamicRepositoryBeanNameGenerator; -import org.springframework.beans.BeansException; -import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; -import org.springframework.beans.factory.support.AbstractBeanDefinition; -import org.springframework.beans.factory.support.BeanDefinitionBuilder; -import org.springframework.beans.factory.support.BeanDefinitionRegistry; -import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; -import org.springframework.core.io.ResourceLoader; -import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean; -import org.springframework.data.rest.core.event.AbstractRepositoryEventListener; -import org.springframework.orm.jpa.EntityManagerFactoryUtils; -import org.springframework.orm.jpa.SharedEntityManagerCreator; -import org.springframework.web.context.WebApplicationContext; -import org.springframework.web.context.support.ServletContextResourceLoader; -import org.springframework.web.context.support.WebApplicationContextUtils; - -import javax.persistence.EntityManager; -import javax.persistence.EntityManagerFactory; -import javax.persistence.metamodel.EntityType; -import javax.servlet.ServletContext; -import java.util.Set; - -import static com.google.common.collect.Sets.newHashSet; -import static com.google.common.collect.Sets.newLinkedHashSet; -import static org.lightadmin.core.config.domain.unit.ConfigurationUnitsConverter.unitsFromAutowiredConfiguration; -import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition; -import static org.springframework.util.StringUtils.tokenizeToStringArray; - -public class LightAdminBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor { - - public static final String JPA_MAPPPING_CONTEXT_BEAN = "jpaMapppingContext"; - public static final String REPOSITORIES_BEAN = "repositories"; - public static final String LIGHTADMIN_CONFIGURATION_BEAN = "lightAdminConfiguration"; - public static final String CONFIGURATION_UNITS_VALIDATOR_BEAN = "configurationUnitsValidator"; - - protected static final String CONFIG_LOCATION_DELIMITERS = ",; \t\n"; - - protected DynamicRepositoryBeanNameGenerator nameGenerator = new DynamicRepositoryBeanNameGenerator(); - protected DynamicRepositoryClassFactory classFactory = new JavassistDynamicJpaRepositoryClassFactory(nameGenerator); - protected ClassScanner classScanner = new AdministrationClassScanner(); - - protected ServletContext servletContext; - - protected String basePackage; - - public LightAdminBeanDefinitionRegistryPostProcessor(String basePackage, ServletContext servletContext) { - this.servletContext = servletContext; - this.basePackage = basePackage; - } - - @Override - public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { - WebApplicationContext rootContext = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext); - - EntityManager entityManager = findEntityManager(rootContext); - - ResourceLoader resourceLoader = newResourceLoader(servletContext); - - Set administrationConfigs = scanPackageForAdministrationClasses(); - - Set configurationUnits = configurationUnits(rootContext, administrationConfigs); - - registry.registerBeanDefinition(JPA_MAPPPING_CONTEXT_BEAN, mappingContext(entityManager)); - - registry.registerBeanDefinition(CONFIGURATION_UNITS_VALIDATOR_BEAN, configurationUnitsValidator(resourceLoader)); - - for (Class managedEntityType : managedEntities(entityManager)) { - Class repoInterface = createDynamicRepositoryClass(managedEntityType, entityManager); - registry.registerBeanDefinition(beanName(repoInterface), repositoryFactory(repoInterface, entityManager)); - } - - registerRepositoryEventListeners(configurationUnits, registry); - - registry.registerBeanDefinition(beanName(GlobalAdministrationConfiguration.class), globalAdministrationConfigurationFactoryBeanDefinition(configurationUnits)); - registry.registerBeanDefinition(beanName(DomainTypeAdministrationConfigurationFactory.class), domainTypeAdministrationConfigurationFactoryDefinition(entityManager)); - } - - private void registerRepositoryEventListeners(Set configurationUnits, BeanDefinitionRegistry registry) { - for (ConfigurationUnits configurationUnit : configurationUnits) { - Class repositoryEventListenerClass = configurationUnit.getEntityConfiguration().getRepositoryEventListener(); - if (repositoryEventListenerClass != null) { - registry.registerBeanDefinition(beanName(repositoryEventListenerClass), repositoryEventListener(repositoryEventListenerClass)); - } - } - } - - private Set configurationUnits(WebApplicationContext rootContext, Set administrationConfigs) { - Set configurationUnitsCollection = newLinkedHashSet(); - for (Class administrationConfig : administrationConfigs) { - ConfigurationUnits configurationUnits = unitsFromAutowiredConfiguration(administrationConfig, rootContext.getAutowireCapableBeanFactory()); - configurationUnitsCollection.add(configurationUnits); - } - return configurationUnitsCollection; - } - - private Iterable> managedEntities(EntityManager entityManager) { - Set> managedEntities = newHashSet(); - for (EntityType entity : entityManager.getMetamodel().getEntities()) { - if (entity.getJavaType() != null) - managedEntities.add(entity.getJavaType()); - } - return managedEntities; - } - - private BeanDefinition repositoryEventListener(Class repositoryEventListener) { - BeanDefinitionBuilder builder = rootBeanDefinition(repositoryEventListener); - builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_AUTODETECT); - return builder.getBeanDefinition(); - } - - private BeanDefinition configurationUnitsValidator(ResourceLoader resourceLoader) { - BeanDefinitionBuilder builder = rootBeanDefinition(CompositeConfigurationUnitsValidator.class); - builder.addConstructorArgReference(JPA_MAPPPING_CONTEXT_BEAN); - builder.addConstructorArgValue(resourceLoader); - builder.addConstructorArgReference(LIGHTADMIN_CONFIGURATION_BEAN); - return builder.getBeanDefinition(); - } - - private BeanDefinition mappingContext(EntityManager entityManager) { - BeanDefinitionBuilder builder = rootBeanDefinition(JpaMetamodelMappingContextFactoryBean.class); - builder.addPropertyValue("entityManager", entityManager); - return builder.getBeanDefinition(); - } - - private BeanDefinition globalAdministrationConfigurationFactoryBeanDefinition(Set configurationUnits) { - BeanDefinitionBuilder builder = rootBeanDefinition(GlobalAdministrationConfigurationFactoryBean.class); - builder.addPropertyReference("domainTypeAdministrationConfigurationFactory", beanName(DomainTypeAdministrationConfigurationFactory.class)); - builder.addPropertyValue("domainTypeConfigurationUnits", configurationUnits); - builder.addPropertyReference("mappingContext", JPA_MAPPPING_CONTEXT_BEAN); - builder.addPropertyReference("repositories", REPOSITORIES_BEAN); - builder.addPropertyReference("configurationUnitsValidator", CONFIGURATION_UNITS_VALIDATOR_BEAN); - return builder.getBeanDefinition(); - } - - private BeanDefinition repositoryFactory(Class repoInterface, EntityManager entityManager) { - BeanDefinitionBuilder builder = rootBeanDefinition(JpaRepositoryFactoryBean.class); - builder.addPropertyValue("entityManager", entityManager); - builder.addPropertyReference("mappingContext", JPA_MAPPPING_CONTEXT_BEAN); - builder.addPropertyValue("repositoryInterface", repoInterface); - return builder.getBeanDefinition(); - } - - private BeanDefinition domainTypeAdministrationConfigurationFactoryDefinition(EntityManager entityManager) { - BeanDefinitionBuilder builder = rootBeanDefinition(DomainTypeAdministrationConfigurationFactory.class); - builder.addConstructorArgReference(REPOSITORIES_BEAN); - builder.addConstructorArgValue(entityManager); - builder.addConstructorArgReference(JPA_MAPPPING_CONTEXT_BEAN); - return builder.getBeanDefinition(); - } - - private EntityManager findEntityManager(WebApplicationContext rootContext) { - EntityManagerFactory entityManagerFactory = EntityManagerFactoryUtils.findEntityManagerFactory(rootContext, null); - - return SharedEntityManagerCreator.createSharedEntityManager(entityManagerFactory); - } - - private ServletContextResourceLoader newResourceLoader(ServletContext servletContext) { - return new ServletContextResourceLoader(servletContext); - } - - private Class createDynamicRepositoryClass(Class domainType, EntityManager entityManager) { - EntityType entityType = entityManager.getMetamodel().entity(domainType); - Class idType = entityType.getIdType().getJavaType(); - - return classFactory.createDynamicRepositoryClass(domainType, idType); - } - - private Set scanPackageForAdministrationClasses() { - final Set administrationConfigs = newLinkedHashSet(); - for (String configurationsBasePackage : configurationsBasePackages()) { - administrationConfigs.addAll(classScanner.scan(configurationsBasePackage)); - } - - return administrationConfigs; - } - - private String[] configurationsBasePackages() { - return tokenizeToStringArray(basePackage, CONFIG_LOCATION_DELIMITERS); - } - - private String beanName(Class type) { - return nameGenerator.generateBeanNameDecapitalized(type); - } - - @Override - public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { - } +/* + * Copyright 2012-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.lightadmin.core.config.bootstrap; + +import org.lightadmin.core.config.bootstrap.parsing.validation.CompositeConfigurationUnitsValidator; +import org.lightadmin.core.config.bootstrap.scanning.AdministrationClassScanner; +import org.lightadmin.core.config.bootstrap.scanning.ClassScanner; +import org.lightadmin.core.config.domain.DomainTypeAdministrationConfigurationFactory; +import org.lightadmin.core.config.domain.GlobalAdministrationConfiguration; +import org.lightadmin.core.config.domain.unit.ConfigurationUnits; +import org.lightadmin.core.persistence.repository.DynamicRepositoryClassFactory; +import org.lightadmin.core.persistence.repository.JavassistDynamicJpaRepositoryClassFactory; +import org.lightadmin.core.util.DynamicRepositoryBeanNameGenerator; +import org.springframework.beans.BeansException; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; +import org.springframework.core.io.ResourceLoader; +import org.springframework.data.jpa.repository.support.JpaRepositoryFactoryBean; +import org.springframework.data.rest.core.event.AbstractRepositoryEventListener; +import org.springframework.orm.jpa.EntityManagerFactoryUtils; +import org.springframework.orm.jpa.SharedEntityManagerCreator; +import org.springframework.web.context.WebApplicationContext; +import org.springframework.web.context.support.ServletContextResourceLoader; +import org.springframework.web.context.support.WebApplicationContextUtils; + +import javax.persistence.EntityManager; +import javax.persistence.EntityManagerFactory; +import javax.persistence.metamodel.EntityType; +import javax.servlet.ServletContext; +import java.util.Set; + +import static com.google.common.collect.Sets.newHashSet; +import static com.google.common.collect.Sets.newLinkedHashSet; +import static org.lightadmin.core.config.domain.unit.ConfigurationUnitsConverter.unitsFromAutowiredConfiguration; +import static org.springframework.beans.factory.support.BeanDefinitionBuilder.rootBeanDefinition; +import static org.springframework.util.StringUtils.tokenizeToStringArray; + +public class LightAdminBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor { + + public static final String JPA_MAPPPING_CONTEXT_BEAN = "jpaMapppingContext"; + public static final String REPOSITORIES_BEAN = "repositories"; + public static final String LIGHTADMIN_CONFIGURATION_BEAN = "lightAdminConfiguration"; + public static final String CONFIGURATION_UNITS_VALIDATOR_BEAN = "configurationUnitsValidator"; + + protected static final String CONFIG_LOCATION_DELIMITERS = ",; \t\n"; + + protected DynamicRepositoryBeanNameGenerator nameGenerator = new DynamicRepositoryBeanNameGenerator(); + protected DynamicRepositoryClassFactory classFactory = new JavassistDynamicJpaRepositoryClassFactory(nameGenerator); + protected ClassScanner classScanner = new AdministrationClassScanner(); + + protected ServletContext servletContext; + + protected String basePackage; + + public LightAdminBeanDefinitionRegistryPostProcessor(String basePackage, ServletContext servletContext) { + this.servletContext = servletContext; + this.basePackage = basePackage; + } + + @Override + public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { + WebApplicationContext rootContext = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext); + + EntityManager entityManager = findEntityManager(rootContext); + + ResourceLoader resourceLoader = newResourceLoader(servletContext); + + Set administrationConfigs = scanPackageForAdministrationClasses(); + + Set configurationUnits = configurationUnits(rootContext, administrationConfigs); + + registry.registerBeanDefinition(JPA_MAPPPING_CONTEXT_BEAN, mappingContext(entityManager)); + + registry.registerBeanDefinition(CONFIGURATION_UNITS_VALIDATOR_BEAN, configurationUnitsValidator(resourceLoader)); + + for (Class managedEntityType : managedEntities(entityManager)) { + Class repoInterface = createDynamicRepositoryClass(managedEntityType, entityManager); + registry.registerBeanDefinition(beanName(repoInterface), repositoryFactory(repoInterface, entityManager)); + } + + registerRepositoryEventListeners(configurationUnits, registry); + + registry.registerBeanDefinition(beanName(GlobalAdministrationConfiguration.class), globalAdministrationConfigurationFactoryBeanDefinition(configurationUnits)); + registry.registerBeanDefinition(beanName(DomainTypeAdministrationConfigurationFactory.class), domainTypeAdministrationConfigurationFactoryDefinition(entityManager)); + } + + private void registerRepositoryEventListeners(Set configurationUnits, BeanDefinitionRegistry registry) { + for (ConfigurationUnits configurationUnit : configurationUnits) { + Class repositoryEventListenerClass = configurationUnit.getEntityConfiguration().getRepositoryEventListener(); + if (repositoryEventListenerClass != null) { + registry.registerBeanDefinition(beanName(repositoryEventListenerClass), repositoryEventListener(repositoryEventListenerClass)); + } + } + } + + private Set configurationUnits(WebApplicationContext rootContext, Set administrationConfigs) { + Set configurationUnitsCollection = newLinkedHashSet(); + for (Class administrationConfig : administrationConfigs) { + ConfigurationUnits configurationUnits = unitsFromAutowiredConfiguration(administrationConfig, rootContext.getAutowireCapableBeanFactory()); + configurationUnitsCollection.add(configurationUnits); + } + return configurationUnitsCollection; + } + + private Iterable> managedEntities(EntityManager entityManager) { + Set> managedEntities = newHashSet(); + for (EntityType entity : entityManager.getMetamodel().getEntities()) { + if (entity.getJavaType() != null) + managedEntities.add(entity.getJavaType()); + } + return managedEntities; + } + + private BeanDefinition repositoryEventListener(Class repositoryEventListener) { + BeanDefinitionBuilder builder = rootBeanDefinition(repositoryEventListener); + builder.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_AUTODETECT); + return builder.getBeanDefinition(); + } + + private BeanDefinition configurationUnitsValidator(ResourceLoader resourceLoader) { + BeanDefinitionBuilder builder = rootBeanDefinition(CompositeConfigurationUnitsValidator.class); + builder.addConstructorArgReference(JPA_MAPPPING_CONTEXT_BEAN); + builder.addConstructorArgValue(resourceLoader); + builder.addConstructorArgReference(LIGHTADMIN_CONFIGURATION_BEAN); + return builder.getBeanDefinition(); + } + + private BeanDefinition mappingContext(EntityManager entityManager) { + BeanDefinitionBuilder builder = rootBeanDefinition(JpaMetamodelMappingContextFactoryBean.class); + builder.addPropertyValue("entityManager", entityManager); + return builder.getBeanDefinition(); + } + + private BeanDefinition globalAdministrationConfigurationFactoryBeanDefinition(Set configurationUnits) { + BeanDefinitionBuilder builder = rootBeanDefinition(GlobalAdministrationConfigurationFactoryBean.class); + builder.addPropertyReference("domainTypeAdministrationConfigurationFactory", beanName(DomainTypeAdministrationConfigurationFactory.class)); + builder.addPropertyValue("domainTypeConfigurationUnits", configurationUnits); + builder.addPropertyReference("mappingContext", JPA_MAPPPING_CONTEXT_BEAN); + builder.addPropertyReference("repositories", REPOSITORIES_BEAN); + builder.addPropertyReference("configurationUnitsValidator", CONFIGURATION_UNITS_VALIDATOR_BEAN); + return builder.getBeanDefinition(); + } + + private BeanDefinition repositoryFactory(Class repoInterface, EntityManager entityManager) { + BeanDefinitionBuilder builder = rootBeanDefinition(JpaRepositoryFactoryBean.class); + builder.addConstructorArgValue(repoInterface); + builder.addPropertyValue("entityManager", entityManager); + builder.addPropertyReference("mappingContext", JPA_MAPPPING_CONTEXT_BEAN); + return builder.getBeanDefinition(); + } + + private BeanDefinition domainTypeAdministrationConfigurationFactoryDefinition(EntityManager entityManager) { + BeanDefinitionBuilder builder = rootBeanDefinition(DomainTypeAdministrationConfigurationFactory.class); + builder.addConstructorArgReference(REPOSITORIES_BEAN); + builder.addConstructorArgValue(entityManager); + builder.addConstructorArgReference(JPA_MAPPPING_CONTEXT_BEAN); + return builder.getBeanDefinition(); + } + + private EntityManager findEntityManager(WebApplicationContext rootContext) { + EntityManagerFactory entityManagerFactory = EntityManagerFactoryUtils.findEntityManagerFactory(rootContext, null); + + return SharedEntityManagerCreator.createSharedEntityManager(entityManagerFactory); + } + + private ServletContextResourceLoader newResourceLoader(ServletContext servletContext) { + return new ServletContextResourceLoader(servletContext); + } + + @SuppressWarnings("unchecked") + private Class createDynamicRepositoryClass(Class domainType, EntityManager entityManager) { + EntityType entityType = entityManager.getMetamodel().entity(domainType); + Class idType = entityType.getIdType().getJavaType(); + + return classFactory.createDynamicRepositoryClass(domainType, idType); + } + + private Set scanPackageForAdministrationClasses() { + final Set administrationConfigs = newLinkedHashSet(); + for (String configurationsBasePackage : configurationsBasePackages()) { + administrationConfigs.addAll(classScanner.scan(configurationsBasePackage)); + } + + return administrationConfigs; + } + + private String[] configurationsBasePackages() { + return tokenizeToStringArray(basePackage, CONFIG_LOCATION_DELIMITERS); + } + + private String beanName(Class type) { + return nameGenerator.generateBeanNameDecapitalized(type); + } + + @Override + public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) { + } } \ No newline at end of file diff --git a/lightadmin-core/src/main/java/org/lightadmin/core/config/context/LightAdminRepositoryRestConfigurer.java b/lightadmin-core/src/main/java/org/lightadmin/core/config/context/LightAdminRepositoryRestConfigurer.java new file mode 100644 index 00000000..f8e77c71 --- /dev/null +++ b/lightadmin-core/src/main/java/org/lightadmin/core/config/context/LightAdminRepositoryRestConfigurer.java @@ -0,0 +1,83 @@ +/** + * + */ +package org.lightadmin.core.config.context; + +import org.lightadmin.core.config.LightAdminConfiguration; +import org.lightadmin.core.config.domain.GlobalAdministrationConfiguration; +import org.lightadmin.core.web.json.LightAdminJacksonModule; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.rest.core.config.RepositoryRestConfiguration; +import org.springframework.data.rest.core.event.ValidatingRepositoryEventListener; +import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer; +import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurerAdapter; +import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration; +import org.springframework.validation.Validator; + +import com.fasterxml.jackson.databind.ObjectMapper; + +/** + * {@link RepositoryRestConfigurer} for LightAdmin. + *

+ * Spring Data Web requires the configurations to be moved out of {@link RepositoryRestMvcConfiguration} + * and are configured through RepositoryRestConfigurer beans + * configured in the context. That's why these configurations are moved out from + * {@link LightAdminRepositoryRestMvcConfiguration} and placed in a separate + * RepositoryRestConfigurer class, which is then configured as a + * bean in the LightAdminRepositoryRestMvcConfiguration. + * + * @author Gazi Rahman + * + */ +@Configuration +public class LightAdminRepositoryRestConfigurer extends RepositoryRestConfigurerAdapter + implements RepositoryRestConfigurer { + private static Logger logger = LoggerFactory.getLogger(LightAdminRepositoryRestConfigurer.class); + + @Autowired + private ListableBeanFactory beanFactory; + + /** + * + */ + public LightAdminRepositoryRestConfigurer() { + logger.debug("LightAdminRepositoryRestConfigurer instantiated"); + } + + @Override + public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) { + config.setDefaultPageSize(10); + config.setBasePath(lightAdminConfiguration().getApplicationRestBasePath()); + config.exposeIdsFor(globalAdministrationConfiguration().getAllDomainTypesAsArray()); + config.setReturnBodyOnCreate(true); + config.setReturnBodyOnUpdate(true); + } + + @Override + public void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener validatingListener) { + validatingListener.addValidator("beforeCreate", validator()); + validatingListener.addValidator("beforeSave", validator()); + } + + @Override + public void configureJacksonObjectMapper(ObjectMapper objectMapper) { + objectMapper.registerModule(new LightAdminJacksonModule(globalAdministrationConfiguration())); + } + + private GlobalAdministrationConfiguration globalAdministrationConfiguration() { + return beanFactory.getBean(GlobalAdministrationConfiguration.class); + } + + private LightAdminConfiguration lightAdminConfiguration() { + return beanFactory.getBean(LightAdminConfiguration.class); + } + + private Validator validator() { + return beanFactory.getBean("validator", Validator.class); + } + +} diff --git a/lightadmin-core/src/main/java/org/lightadmin/core/config/context/LightAdminRepositoryRestMvcConfiguration.java b/lightadmin-core/src/main/java/org/lightadmin/core/config/context/LightAdminRepositoryRestMvcConfiguration.java index e643bb56..7488ca83 100644 --- a/lightadmin-core/src/main/java/org/lightadmin/core/config/context/LightAdminRepositoryRestMvcConfiguration.java +++ b/lightadmin-core/src/main/java/org/lightadmin/core/config/context/LightAdminRepositoryRestMvcConfiguration.java @@ -1,185 +1,165 @@ -/* - * Copyright 2012-2014 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.lightadmin.core.config.context; - -import com.fasterxml.jackson.databind.ObjectMapper; -import org.lightadmin.core.config.LightAdminConfiguration; -import org.lightadmin.core.config.bootstrap.RepositoriesFactoryBean; -import org.lightadmin.core.config.domain.GlobalAdministrationConfiguration; -import org.lightadmin.core.persistence.repository.event.FileManipulationRepositoryEventListener; -import org.lightadmin.core.persistence.repository.invoker.DynamicRepositoryInvokerFactory; -import org.lightadmin.core.persistence.support.DynamicDomainObjectMerger; -import org.lightadmin.core.storage.FileResourceStorage; -import org.lightadmin.core.web.json.DomainTypeToJsonMetadataConverter; -import org.lightadmin.core.web.json.LightAdminJacksonModule; -import org.lightadmin.core.web.support.*; -import org.springframework.beans.BeanInstantiationException; -import org.springframework.beans.factory.ListableBeanFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.context.annotation.Configuration; -import org.springframework.data.repository.support.Repositories; -import org.springframework.data.rest.core.config.RepositoryRestConfiguration; -import org.springframework.data.rest.core.event.ValidatingRepositoryEventListener; -import org.springframework.data.rest.core.invoke.RepositoryInvokerFactory; -import org.springframework.data.rest.core.support.DomainObjectMerger; -import org.springframework.data.rest.webmvc.RepositoryRestController; -import org.springframework.data.rest.webmvc.config.PersistentEntityResourceAssemblerArgumentResolver; -import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration; -import org.springframework.validation.Validator; -import org.springframework.web.method.support.HandlerMethodArgumentResolver; -import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; - -import java.util.List; - -import static com.google.common.collect.Lists.newLinkedList; -import static org.springframework.beans.PropertyAccessorFactory.forDirectFieldAccess; -import static org.springframework.util.ClassUtils.isAssignableValue; - -@Configuration -@ComponentScan(basePackages = {"org.lightadmin.core.web"}, - includeFilters = @ComponentScan.Filter(RepositoryRestController.class), useDefaultFilters = false) -public class LightAdminRepositoryRestMvcConfiguration extends RepositoryRestMvcConfiguration { - - @Autowired - private ListableBeanFactory beanFactory; - - @Bean - public DomainEntityLinks domainEntityLinks() { - return new DomainEntityLinks(globalAdministrationConfiguration(), backendIdConverterRegistry(), lightAdminConfiguration()); - } - - @Bean - public DynamicRepositoryEntityLinks dynamicRepositoryEntityLinks() { - return DynamicRepositoryEntityLinks.wrap(super.entityLinks()); - } - - @Bean - public DynamicPersistentEntityResourceProcessor dynamicPersistentEntityResourceProcessor() { - return new DynamicPersistentEntityResourceProcessor(globalAdministrationConfiguration(), fileResourceStorage(), dynamicRepositoryEntityLinks(), domainEntityLinks(), resourceMappings()); - } - - @Bean - public DomainTypeToJsonMetadataConverter domainTypeToJsonMetadataConverter() { - return new DomainTypeToJsonMetadataConverter(globalAdministrationConfiguration(), entityLinks()); - } - - @Bean - public Repositories repositories() { - try { - return new RepositoriesFactoryBean(beanFactory).getObject(); - } catch (Exception e) { - throw new BeanInstantiationException(Repositories.class, "Repositories bean instantiation problem!", e); - } - } - - @Bean - public DomainObjectMerger domainObjectMerger() throws Exception { - return new DynamicDomainObjectMerger(repositories(), defaultConversionService(), globalAdministrationConfiguration()); - } - - @Bean - public RepositoryInvokerFactory repositoryInvokerFactory() { - RepositoryInvokerFactory repositoryInvokerFactory = super.repositoryInvokerFactory(); - - return new DynamicRepositoryInvokerFactory(repositories(), repositoryInvokerFactory); - } - - @Bean - public ConfigurationHandlerMethodArgumentResolver configurationHandlerMethodArgumentResolver() { - return new ConfigurationHandlerMethodArgumentResolver(globalAdministrationConfiguration(), resourceMetadataHandlerMethodArgumentResolver()); - } - - @Bean - @Autowired - public FileManipulationRepositoryEventListener domainRepositoryEventListener(GlobalAdministrationConfiguration configuration, FileResourceStorage fileResourceStorage) { - return new FileManipulationRepositoryEventListener(configuration, fileResourceStorage); - } - - @Override - protected void configureRepositoryRestConfiguration(RepositoryRestConfiguration config) { - config.setDefaultPageSize(10); - config.setBaseUri(lightAdminConfiguration().getApplicationRestBaseUrl()); - config.exposeIdsFor(globalAdministrationConfiguration().getAllDomainTypesAsArray()); - config.setReturnBodyOnCreate(true); - config.setReturnBodyOnUpdate(true); - } - - @Override - public RequestMappingHandlerAdapter repositoryExporterHandlerAdapter() { - RequestMappingHandlerAdapter requestMappingHandlerAdapter = super.repositoryExporterHandlerAdapter(); - configureRepositoryExporterHandlerAdapter(requestMappingHandlerAdapter); - return requestMappingHandlerAdapter; - } - - @Override - protected void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener validatingListener) { - validatingListener.addValidator("beforeCreate", validator()); - validatingListener.addValidator("beforeSave", validator()); - } - - @Override - public void addArgumentResolvers(List argumentResolvers) { - super.addArgumentResolvers(argumentResolvers); - argumentResolvers.add(configurationHandlerMethodArgumentResolver()); - } - - @Override - protected void configureJacksonObjectMapper(ObjectMapper objectMapper) { - objectMapper.registerModule(new LightAdminJacksonModule(globalAdministrationConfiguration())); - } - - @SuppressWarnings("unchecked") - private void configureRepositoryExporterHandlerAdapter(RequestMappingHandlerAdapter requestMappingHandlerAdapter) { - List defaultArgumentResolvers = (List) forDirectFieldAccess(requestMappingHandlerAdapter).getPropertyValue("argumentResolvers"); - - List argumentResolvers = decorateArgumentResolvers(defaultArgumentResolvers); - - argumentResolvers.add(configurationHandlerMethodArgumentResolver()); - - forDirectFieldAccess(requestMappingHandlerAdapter).setPropertyValue("argumentResolvers", argumentResolvers); - } - - private List decorateArgumentResolvers(List argumentResolvers) { - List result = newLinkedList(); - for (HandlerMethodArgumentResolver argumentResolver : argumentResolvers) { - if (isAssignableValue(PersistentEntityResourceAssemblerArgumentResolver.class, argumentResolver)) { - PersistentEntityResourceAssemblerArgumentResolver persistentEntityResourceAssemblerArgumentResolver = (PersistentEntityResourceAssemblerArgumentResolver) argumentResolver; - result.add(new DynamicPersistentEntityResourceAssemblerArgumentResolver(persistentEntityResourceAssemblerArgumentResolver)); - continue; - } - result.add(argumentResolver); - } - return result; - } - - private GlobalAdministrationConfiguration globalAdministrationConfiguration() { - return beanFactory.getBean(GlobalAdministrationConfiguration.class); - } - - private FileResourceStorage fileResourceStorage() { - return beanFactory.getBean(FileResourceStorage.class); - } - - private Validator validator() { - return beanFactory.getBean("validator", Validator.class); - } - - private LightAdminConfiguration lightAdminConfiguration() { - return beanFactory.getBean(LightAdminConfiguration.class); - } +/* + * Copyright 2012-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.lightadmin.core.config.context; + +import org.lightadmin.core.config.LightAdminConfiguration; +import org.lightadmin.core.config.bootstrap.RepositoriesFactoryBean; +import org.lightadmin.core.config.domain.GlobalAdministrationConfiguration; +import org.lightadmin.core.persistence.repository.event.FileManipulationRepositoryEventListener; +import org.lightadmin.core.persistence.repository.invoker.DynamicRepositoryInvokerFactory; +import org.lightadmin.core.persistence.support.DynamicDomainObjectMerger; +import org.lightadmin.core.storage.FileResourceStorage; +import org.lightadmin.core.web.json.DomainTypeToJsonMetadataConverter; +import org.lightadmin.core.web.support.*; +import org.springframework.beans.BeanInstantiationException; +import org.springframework.beans.factory.ListableBeanFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.convert.ConversionService; +import org.springframework.data.repository.support.Repositories; +import org.springframework.data.repository.support.RepositoryInvokerFactory; +import org.springframework.data.rest.core.support.DomainObjectMerger; +import org.springframework.data.rest.webmvc.RepositoryRestController; +import org.springframework.data.rest.webmvc.config.PersistentEntityResourceAssemblerArgumentResolver; +import org.springframework.data.rest.webmvc.config.RepositoryRestConfigurer; +import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration; +import org.springframework.data.rest.webmvc.mapping.LinkCollector; +import org.springframework.web.method.support.HandlerMethodArgumentResolver; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; + +import java.util.List; + +import static com.google.common.collect.Lists.newLinkedList; +import static org.springframework.beans.PropertyAccessorFactory.forDirectFieldAccess; +import static org.springframework.util.ClassUtils.isAssignableValue; + +@Configuration +@ComponentScan(basePackages = {"org.lightadmin.core.web"}, + includeFilters = @ComponentScan.Filter(RepositoryRestController.class), useDefaultFilters = false) +public class LightAdminRepositoryRestMvcConfiguration extends RepositoryRestMvcConfiguration { + + @Autowired + private ListableBeanFactory beanFactory; + + @Bean + public DomainEntityLinks domainEntityLinks() { + return new DomainEntityLinks(globalAdministrationConfiguration(), backendIdConverterRegistry(), lightAdminConfiguration()); + } + + @Override + public DynamicRepositoryEntityLinks entityLinks() { + return new DynamicRepositoryEntityLinks(super.entityLinks()); + } + + @Bean + public DynamicPersistentEntityResourceProcessor dynamicPersistentEntityResourceProcessor() { + return new DynamicPersistentEntityResourceProcessor(globalAdministrationConfiguration(), + fileResourceStorage(), entityLinks(), domainEntityLinks(), + resourceMappings(), associationLinks()); + } + + @Bean + public DomainTypeToJsonMetadataConverter domainTypeToJsonMetadataConverter() { + return new DomainTypeToJsonMetadataConverter(globalAdministrationConfiguration(), entityLinks()); + } + + @Bean + public Repositories repositories() { + try { + return new RepositoriesFactoryBean(beanFactory).getObject(); + } catch (Exception e) { + throw new BeanInstantiationException(Repositories.class, "Repositories bean instantiation problem!", e); + } + } + + @Bean + public DomainObjectMerger domainObjectMerger() throws Exception { + return new DynamicDomainObjectMerger(repositories(), defaultConversionService(), globalAdministrationConfiguration()); + } + + @Override + public RepositoryInvokerFactory repositoryInvokerFactory(@Qualifier ConversionService defaultConversionService) { + RepositoryInvokerFactory repositoryInvokerFactory = super.repositoryInvokerFactory(defaultConversionService); + + return new DynamicRepositoryInvokerFactory(repositories(), repositoryInvokerFactory); + } + + @Bean + public ConfigurationHandlerMethodArgumentResolver configurationHandlerMethodArgumentResolver() { + return new ConfigurationHandlerMethodArgumentResolver(globalAdministrationConfiguration(), resourceMetadataHandlerMethodArgumentResolver()); + } + + @Bean + @Autowired + public FileManipulationRepositoryEventListener domainRepositoryEventListener(GlobalAdministrationConfiguration configuration, FileResourceStorage fileResourceStorage) { + return new FileManipulationRepositoryEventListener(configuration, fileResourceStorage); + } + + @Bean + public RepositoryRestConfigurer lightAdminRepositoryRestConfigurer() { + return new LightAdminRepositoryRestConfigurer(); + } + + @Override + public RequestMappingHandlerAdapter repositoryExporterHandlerAdapter() { + RequestMappingHandlerAdapter requestMappingHandlerAdapter = super.repositoryExporterHandlerAdapter(); + configureRepositoryExporterHandlerAdapter(requestMappingHandlerAdapter); + return requestMappingHandlerAdapter; + } + + @Override + public void addArgumentResolvers(List argumentResolvers) { + super.addArgumentResolvers(argumentResolvers); + argumentResolvers.add(configurationHandlerMethodArgumentResolver()); + } + + @Override + protected LinkCollector linkCollector() { + return new LightAdminLinkCollector(persistentEntities(), selfLinkProvider(), associationLinks()); + } + + @SuppressWarnings("unchecked") + private void configureRepositoryExporterHandlerAdapter(RequestMappingHandlerAdapter requestMappingHandlerAdapter) { + List defaultArgumentResolvers = (List) forDirectFieldAccess(requestMappingHandlerAdapter).getPropertyValue("argumentResolvers"); + + List argumentResolvers = decorateArgumentResolvers(defaultArgumentResolvers); + + argumentResolvers.add(configurationHandlerMethodArgumentResolver()); + + forDirectFieldAccess(requestMappingHandlerAdapter).setPropertyValue("argumentResolvers", argumentResolvers); + } + + private List decorateArgumentResolvers(List argumentResolvers) { + List result = newLinkedList(); + result.addAll(argumentResolvers); + return result; + } + + private GlobalAdministrationConfiguration globalAdministrationConfiguration() { + return beanFactory.getBean(GlobalAdministrationConfiguration.class); + } + + private FileResourceStorage fileResourceStorage() { + return beanFactory.getBean(FileResourceStorage.class); + } + + private LightAdminConfiguration lightAdminConfiguration() { + return beanFactory.getBean(LightAdminConfiguration.class); + } } \ No newline at end of file diff --git a/lightadmin-core/src/main/java/org/lightadmin/core/config/context/LightAdminSecurityConfiguration.java b/lightadmin-core/src/main/java/org/lightadmin/core/config/context/LightAdminSecurityConfiguration.java index 732790a0..0b129707 100644 --- a/lightadmin-core/src/main/java/org/lightadmin/core/config/context/LightAdminSecurityConfiguration.java +++ b/lightadmin-core/src/main/java/org/lightadmin/core/config/context/LightAdminSecurityConfiguration.java @@ -1,211 +1,213 @@ -/* - * Copyright 2012-2014 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.lightadmin.core.config.context; - -import org.lightadmin.core.config.LightAdminConfiguration; -import org.lightadmin.core.web.security.LightAdminRequestCache; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Primary; -import org.springframework.core.io.Resource; -import org.springframework.core.io.support.PropertiesLoaderUtils; -import org.springframework.security.access.AccessDecisionVoter; -import org.springframework.security.access.ConfigAttribute; -import org.springframework.security.access.SecurityConfig; -import org.springframework.security.access.vote.AffirmativeBased; -import org.springframework.security.access.vote.RoleVoter; -import org.springframework.security.authentication.AuthenticationManager; -import org.springframework.security.authentication.AuthenticationProvider; -import org.springframework.security.authentication.ProviderManager; -import org.springframework.security.authentication.RememberMeAuthenticationProvider; -import org.springframework.security.authentication.dao.DaoAuthenticationProvider; -import org.springframework.security.authentication.encoding.ShaPasswordEncoder; -import org.springframework.security.core.userdetails.UserDetailsService; -import org.springframework.security.provisioning.InMemoryUserDetailsManager; -import org.springframework.security.web.DefaultSecurityFilterChain; -import org.springframework.security.web.FilterChainProxy; -import org.springframework.security.web.SecurityFilterChain; -import org.springframework.security.web.access.AccessDeniedHandlerImpl; -import org.springframework.security.web.access.ExceptionTranslationFilter; -import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource; -import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; -import org.springframework.security.web.access.intercept.FilterSecurityInterceptor; -import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; -import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; -import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; -import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; -import org.springframework.security.web.authentication.logout.LogoutFilter; -import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; -import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices; -import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter; -import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices; -import org.springframework.security.web.context.HttpSessionSecurityContextRepository; -import org.springframework.security.web.context.SecurityContextPersistenceFilter; -import org.springframework.security.web.savedrequest.RequestCache; -import org.springframework.security.web.util.matcher.AntPathRequestMatcher; -import org.springframework.security.web.util.matcher.AnyRequestMatcher; -import org.springframework.security.web.util.matcher.RequestMatcher; - -import javax.servlet.Filter; -import java.io.IOException; -import java.util.Collection; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Properties; - -import static com.google.common.collect.Lists.newArrayList; -import static com.google.common.collect.Maps.newLinkedHashMap; -import static java.util.Arrays.asList; - -@Configuration -public class LightAdminSecurityConfiguration { - - private static final String REMEMBER_ME_DIGEST_KEY = "LightAdmin"; - private static final String ROLE_ADMIN = "ROLE_ADMIN"; - - private static final String[] PUBLIC_RESOURCES = { - "/images/**", "/scripts/**", "/styles/**", - "/rest/**/file", - "/login", "/page-not-found", "/access-denied", - "/dynamic/logo" - }; - - @Value("classpath:users.properties") - private Resource usersResource; - - @Autowired - private LightAdminConfiguration lightAdminConfiguration; - - @Bean - @Autowired - public FilterChainProxy springSecurityFilterChain(Filter filterSecurityInterceptor, Filter authenticationFilter, Filter rememberMeAuthenticationFilter, Filter logoutFilter, Filter exceptionTranslationFilter, Filter securityContextPersistenceFilter) { - List filterChains = newArrayList(); - for (String pattern : PUBLIC_RESOURCES) { - filterChains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher(applicationUrl(pattern)))); - } - - filterChains.add(new DefaultSecurityFilterChain(AnyRequestMatcher.INSTANCE, securityContextPersistenceFilter, exceptionTranslationFilter, logoutFilter, authenticationFilter, rememberMeAuthenticationFilter, filterSecurityInterceptor)); - - return new FilterChainProxy(filterChains); - } - - @Bean - @Autowired - public Filter filterSecurityInterceptor(AuthenticationManager authenticationManager) throws Exception { - FilterSecurityInterceptor filter = new FilterSecurityInterceptor(); - filter.setAuthenticationManager(authenticationManager); - filter.setAccessDecisionManager(new AffirmativeBased(asList((AccessDecisionVoter) new RoleVoter()))); - filter.setSecurityMetadataSource(securityMetadataSource()); - filter.afterPropertiesSet(); - return filter; - } - - private FilterInvocationSecurityMetadataSource securityMetadataSource() { - LinkedHashMap> map = newLinkedHashMap(); - map.put(AnyRequestMatcher.INSTANCE, asList((ConfigAttribute) new SecurityConfig(ROLE_ADMIN))); - return new DefaultFilterInvocationSecurityMetadataSource(map); - } - - @Bean - @Autowired - public Filter authenticationFilter(AuthenticationManager authenticationManager, RequestCache requestCache) { - UsernamePasswordAuthenticationFilter authenticationFilter = new UsernamePasswordAuthenticationFilter(); - authenticationFilter.setFilterProcessesUrl(applicationUrl("/j_spring_security_check")); - authenticationFilter.setAuthenticationManager(authenticationManager); - SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler(); - successHandler.setRequestCache(requestCache); - authenticationFilter.setAuthenticationSuccessHandler(successHandler); - authenticationFilter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler(applicationUrl("/login?login_error=1"))); - return authenticationFilter; - } - - @Bean - public Filter exceptionTranslationFilter(RequestCache requestCache) { - AccessDeniedHandlerImpl accessDeniedHandler = new AccessDeniedHandlerImpl(); - accessDeniedHandler.setErrorPage(applicationUrl("/access-denied")); - LoginUrlAuthenticationEntryPoint authenticationEntryPoint = new LoginUrlAuthenticationEntryPoint(applicationUrl("/login")); - ExceptionTranslationFilter exceptionTranslationFilter = new ExceptionTranslationFilter(authenticationEntryPoint, requestCache); - exceptionTranslationFilter.setAccessDeniedHandler(accessDeniedHandler); - return exceptionTranslationFilter; - } - - @Bean - public Filter logoutFilter() { - SecurityContextLogoutHandler logoutHandler = new SecurityContextLogoutHandler(); - logoutHandler.setInvalidateHttpSession(false); - LogoutFilter logoutFilter = new LogoutFilter(applicationUrl("/"), logoutHandler); - logoutFilter.setFilterProcessesUrl(applicationUrl("/logout")); - return logoutFilter; - } - - @Bean - public Filter securityContextPersistenceFilter() { - HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository(); - repo.setSpringSecurityContextKey(keyWithNamespace(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY)); - return new SecurityContextPersistenceFilter(repo); - } - - @Bean - public Filter rememberMeAuthenticationFilter(AuthenticationManager authenticationManager, UserDetailsService userDetailsService) { - TokenBasedRememberMeServices rememberMeServices = new TokenBasedRememberMeServices(REMEMBER_ME_DIGEST_KEY, userDetailsService); - rememberMeServices.setCookieName(keyWithNamespace(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY)); - return new RememberMeAuthenticationFilter(authenticationManager, rememberMeServices); - } - - @Bean - public RequestCache requestCache() { - return new LightAdminRequestCache(); - } - - @Bean - @Autowired - public AuthenticationManager authenticationManager(AuthenticationProvider authenticationProvider, AuthenticationProvider rememberMeAuthenticationProvider) { - return new ProviderManager(asList(authenticationProvider, rememberMeAuthenticationProvider)); - } - - @Bean - @Autowired - public AuthenticationProvider authenticationProvider(UserDetailsService usersService) throws Exception { - DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); - provider.setPasswordEncoder(new ShaPasswordEncoder()); - provider.setUserDetailsService(usersService); - provider.afterPropertiesSet(); - return provider; - } - - @Bean - @Primary - public UserDetailsService userDetailsService() throws IOException { - Properties usersPproperties = PropertiesLoaderUtils.loadProperties(usersResource); - return new InMemoryUserDetailsManager(usersPproperties); - } - - @Bean - public AuthenticationProvider rememberMeAuthenticationProvider() { - return new RememberMeAuthenticationProvider(REMEMBER_ME_DIGEST_KEY); - } - - private String applicationUrl(String path) { - return lightAdminConfiguration.getApplicationUrl(path); - } - - private String keyWithNamespace(String key) { - return "lightadmin:" + key; - } - -} +/* + * Copyright 2012-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.lightadmin.core.config.context; + +import org.lightadmin.core.config.LightAdminConfiguration; +import org.lightadmin.core.web.security.LightAdminRequestCache; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PropertiesLoaderUtils; +import org.springframework.security.access.AccessDecisionVoter; +import org.springframework.security.access.ConfigAttribute; +import org.springframework.security.access.SecurityConfig; +import org.springframework.security.access.vote.AffirmativeBased; +import org.springframework.security.access.vote.RoleVoter; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.authentication.ProviderManager; +import org.springframework.security.authentication.RememberMeAuthenticationProvider; +import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +import org.springframework.security.authentication.encoding.ShaPasswordEncoder; +import org.springframework.security.core.userdetails.UserDetailsService; +import org.springframework.security.provisioning.InMemoryUserDetailsManager; +import org.springframework.security.web.DefaultSecurityFilterChain; +import org.springframework.security.web.FilterChainProxy; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.access.AccessDeniedHandlerImpl; +import org.springframework.security.web.access.ExceptionTranslationFilter; +import org.springframework.security.web.access.intercept.DefaultFilterInvocationSecurityMetadataSource; +import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource; +import org.springframework.security.web.access.intercept.FilterSecurityInterceptor; +import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; +import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler; +import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; +import org.springframework.security.web.authentication.logout.LogoutFilter; +import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler; +import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices; +import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter; +import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices; +import org.springframework.security.web.context.HttpSessionSecurityContextRepository; +import org.springframework.security.web.context.SecurityContextPersistenceFilter; +import org.springframework.security.web.savedrequest.RequestCache; +import org.springframework.security.web.util.matcher.AntPathRequestMatcher; +import org.springframework.security.web.util.matcher.AnyRequestMatcher; +import org.springframework.security.web.util.matcher.RequestMatcher; + +import javax.servlet.Filter; +import java.io.IOException; +import java.util.Collection; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Properties; + +import static com.google.common.collect.Lists.newArrayList; +import static com.google.common.collect.Maps.newLinkedHashMap; +import static java.util.Arrays.asList; + +@Configuration +public class LightAdminSecurityConfiguration { + + private static final String REMEMBER_ME_DIGEST_KEY = "LightAdmin"; + private static final String ROLE_ADMIN = "ROLE_ADMIN"; + + private static final String[] PUBLIC_RESOURCES = { + "/images/**", "/scripts/**", "/styles/**", + "/rest/**/file", + "/login", "/page-not-found", "/access-denied", + "/dynamic/logo" + }; + + @Value("classpath:users.properties") + private Resource usersResource; + + @Autowired + private LightAdminConfiguration lightAdminConfiguration; + + @Bean + @Autowired + public FilterChainProxy springSecurityFilterChain(Filter filterSecurityInterceptor, Filter authenticationFilter, Filter rememberMeAuthenticationFilter, Filter logoutFilter, Filter exceptionTranslationFilter, Filter securityContextPersistenceFilter) { + List filterChains = newArrayList(); + for (String pattern : PUBLIC_RESOURCES) { + filterChains.add(new DefaultSecurityFilterChain(new AntPathRequestMatcher(applicationUrl(pattern)))); + } + + filterChains.add(new DefaultSecurityFilterChain(AnyRequestMatcher.INSTANCE, securityContextPersistenceFilter, exceptionTranslationFilter, logoutFilter, authenticationFilter, rememberMeAuthenticationFilter, filterSecurityInterceptor)); + + return new FilterChainProxy(filterChains); + } + + @Bean + @Autowired + public Filter filterSecurityInterceptor(AuthenticationManager authenticationManager) throws Exception { + FilterSecurityInterceptor filter = new FilterSecurityInterceptor(); + filter.setAuthenticationManager(authenticationManager); + List> decisionVoters = asList((AccessDecisionVoter) new RoleVoter()); + AffirmativeBased accessDecisionManager = new AffirmativeBased(decisionVoters); + filter.setAccessDecisionManager(accessDecisionManager); + filter.setSecurityMetadataSource(securityMetadataSource()); + filter.afterPropertiesSet(); + return filter; + } + + private FilterInvocationSecurityMetadataSource securityMetadataSource() { + LinkedHashMap> map = newLinkedHashMap(); + map.put(AnyRequestMatcher.INSTANCE, asList((ConfigAttribute) new SecurityConfig(ROLE_ADMIN))); + return new DefaultFilterInvocationSecurityMetadataSource(map); + } + + @Bean + @Autowired + public Filter authenticationFilter(AuthenticationManager authenticationManager, RequestCache requestCache) { + UsernamePasswordAuthenticationFilter authenticationFilter = new UsernamePasswordAuthenticationFilter(); + authenticationFilter.setFilterProcessesUrl(applicationUrl("/j_spring_security_check")); + authenticationFilter.setAuthenticationManager(authenticationManager); + SavedRequestAwareAuthenticationSuccessHandler successHandler = new SavedRequestAwareAuthenticationSuccessHandler(); + successHandler.setRequestCache(requestCache); + authenticationFilter.setAuthenticationSuccessHandler(successHandler); + authenticationFilter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler(applicationUrl("/login?login_error=1"))); + return authenticationFilter; + } + + @Bean + public Filter exceptionTranslationFilter(RequestCache requestCache) { + AccessDeniedHandlerImpl accessDeniedHandler = new AccessDeniedHandlerImpl(); + accessDeniedHandler.setErrorPage(applicationUrl("/access-denied")); + LoginUrlAuthenticationEntryPoint authenticationEntryPoint = new LoginUrlAuthenticationEntryPoint(applicationUrl("/login")); + ExceptionTranslationFilter exceptionTranslationFilter = new ExceptionTranslationFilter(authenticationEntryPoint, requestCache); + exceptionTranslationFilter.setAccessDeniedHandler(accessDeniedHandler); + return exceptionTranslationFilter; + } + + @Bean + public Filter logoutFilter() { + SecurityContextLogoutHandler logoutHandler = new SecurityContextLogoutHandler(); + logoutHandler.setInvalidateHttpSession(false); + LogoutFilter logoutFilter = new LogoutFilter(applicationUrl("/"), logoutHandler); + logoutFilter.setFilterProcessesUrl(applicationUrl("/logout")); + return logoutFilter; + } + + @Bean + public Filter securityContextPersistenceFilter() { + HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository(); + repo.setSpringSecurityContextKey(keyWithNamespace(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY)); + return new SecurityContextPersistenceFilter(repo); + } + + @Bean + public Filter rememberMeAuthenticationFilter(AuthenticationManager authenticationManager, UserDetailsService userDetailsService) { + TokenBasedRememberMeServices rememberMeServices = new TokenBasedRememberMeServices(REMEMBER_ME_DIGEST_KEY, userDetailsService); + rememberMeServices.setCookieName(keyWithNamespace(AbstractRememberMeServices.SPRING_SECURITY_REMEMBER_ME_COOKIE_KEY)); + return new RememberMeAuthenticationFilter(authenticationManager, rememberMeServices); + } + + @Bean + public RequestCache requestCache() { + return new LightAdminRequestCache(); + } + + @Bean + @Autowired + public AuthenticationManager authenticationManager(AuthenticationProvider authenticationProvider, AuthenticationProvider rememberMeAuthenticationProvider) { + return new ProviderManager(asList(authenticationProvider, rememberMeAuthenticationProvider)); + } + + @Bean + @Autowired + public AuthenticationProvider authenticationProvider(UserDetailsService usersService) throws Exception { + DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); + provider.setPasswordEncoder(new ShaPasswordEncoder()); + provider.setUserDetailsService(usersService); + provider.afterPropertiesSet(); + return provider; + } + + @Bean + @Primary + public UserDetailsService userDetailsService() throws IOException { + Properties usersPproperties = PropertiesLoaderUtils.loadProperties(usersResource); + return new InMemoryUserDetailsManager(usersPproperties); + } + + @Bean + public AuthenticationProvider rememberMeAuthenticationProvider() { + return new RememberMeAuthenticationProvider(REMEMBER_ME_DIGEST_KEY); + } + + private String applicationUrl(String path) { + return lightAdminConfiguration.getApplicationUrl(path); + } + + private String keyWithNamespace(String key) { + return "lightadmin:" + key; + } + +} diff --git a/lightadmin-core/src/main/java/org/lightadmin/core/config/domain/unit/DomainConfigurationUnitType.java b/lightadmin-core/src/main/java/org/lightadmin/core/config/domain/unit/DomainConfigurationUnitType.java index 33ddd47a..b6d46b2d 100644 --- a/lightadmin-core/src/main/java/org/lightadmin/core/config/domain/unit/DomainConfigurationUnitType.java +++ b/lightadmin-core/src/main/java/org/lightadmin/core/config/domain/unit/DomainConfigurationUnitType.java @@ -1,55 +1,60 @@ -/* - * Copyright 2012-2014 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.lightadmin.core.config.domain.unit; - -import static java.lang.String.format; - -public enum DomainConfigurationUnitType { - - SCREEN_CONTEXT("screenContext"), - CONFIGURATION("configuration"), - LIST_VIEW("listView"), - SHOW_VIEW("showView"), - FORM_VIEW("formView"), - QUICK_VIEW("quickView"), - SCOPES("scopes"), - FILTERS("filters"), - SIDEBARS("sidebars"); - - private final String name; - - private DomainConfigurationUnitType(final String name) { - this.name = name; - } - - public String getName() { - return name; - } - - public static DomainConfigurationUnitType forName(String name) { - for (DomainConfigurationUnitType domainConfigurationUnitType : values()) { - if (domainConfigurationUnitType.getName().equals(name)) { - return domainConfigurationUnitType; - } - } - throw new IllegalArgumentException(format("Configuration Unit for name %s not defined!", name)); - } - - @Override - public String toString() { - return getName(); - } +/* + * Copyright 2012-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.lightadmin.core.config.domain.unit; + +import static java.lang.String.format; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonValue; + +public enum DomainConfigurationUnitType { + + SCREEN_CONTEXT("screenContext"), + CONFIGURATION("configuration"), + LIST_VIEW("listView"), + SHOW_VIEW("showView"), + FORM_VIEW("formView"), + QUICK_VIEW("quickView"), + SCOPES("scopes"), + FILTERS("filters"), + SIDEBARS("sidebars"); + + private final String name; + + private DomainConfigurationUnitType(final String name) { + this.name = name; + } + + @JsonValue + public String getName() { + return name; + } + + @JsonCreator + public static DomainConfigurationUnitType forName(String name) { + for (DomainConfigurationUnitType domainConfigurationUnitType : values()) { + if (domainConfigurationUnitType.getName().equals(name)) { + return domainConfigurationUnitType; + } + } + throw new IllegalArgumentException(format("Configuration Unit for name %s not defined!", name)); + } + + @Override + public String toString() { + return getName(); + } } \ No newline at end of file diff --git a/lightadmin-core/src/main/java/org/lightadmin/core/persistence/repository/invoker/DynamicRepositoryInvoker.java b/lightadmin-core/src/main/java/org/lightadmin/core/persistence/repository/invoker/DynamicRepositoryInvoker.java index 7747c811..0b19154f 100644 --- a/lightadmin-core/src/main/java/org/lightadmin/core/persistence/repository/invoker/DynamicRepositoryInvoker.java +++ b/lightadmin-core/src/main/java/org/lightadmin/core/persistence/repository/invoker/DynamicRepositoryInvoker.java @@ -1,35 +1,35 @@ -/* - * Copyright 2012-2014 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.lightadmin.core.persistence.repository.invoker; - -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Sort; -import org.springframework.data.jpa.domain.Specification; -import org.springframework.data.rest.core.invoke.RepositoryInvoker; - -import java.util.List; - -public interface DynamicRepositoryInvoker extends RepositoryInvoker { - - Page findAll(Specification spec, Pageable pageable); - - List findAll(Specification spec, Sort sort); - - List findAll(Specification spec); - - long count(Specification spec); +/* + * Copyright 2012-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.lightadmin.core.persistence.repository.invoker; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.repository.support.RepositoryInvoker; + +import java.util.List; + +public interface DynamicRepositoryInvoker extends RepositoryInvoker { + + Page findAll(Specification spec, Pageable pageable); + + List findAll(Specification spec, Sort sort); + + List findAll(Specification spec); + + long count(Specification spec); } \ No newline at end of file diff --git a/lightadmin-core/src/main/java/org/lightadmin/core/persistence/repository/invoker/DynamicRepositoryInvokerFactory.java b/lightadmin-core/src/main/java/org/lightadmin/core/persistence/repository/invoker/DynamicRepositoryInvokerFactory.java index a58a6faf..5dc08726 100644 --- a/lightadmin-core/src/main/java/org/lightadmin/core/persistence/repository/invoker/DynamicRepositoryInvokerFactory.java +++ b/lightadmin-core/src/main/java/org/lightadmin/core/persistence/repository/invoker/DynamicRepositoryInvokerFactory.java @@ -1,40 +1,40 @@ -/* - * Copyright 2012-2014 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.lightadmin.core.persistence.repository.invoker; - -import org.lightadmin.core.persistence.repository.DynamicJpaRepository; -import org.springframework.data.repository.support.Repositories; -import org.springframework.data.rest.core.invoke.RepositoryInvoker; -import org.springframework.data.rest.core.invoke.RepositoryInvokerFactory; - -public class DynamicRepositoryInvokerFactory implements RepositoryInvokerFactory { - - private final RepositoryInvokerFactory delegate; - private final Repositories repositories; - - public DynamicRepositoryInvokerFactory(Repositories repositories, RepositoryInvokerFactory repositoryInvokerFactory) { - this.repositories = repositories; - this.delegate = repositoryInvokerFactory; - } - - @Override - public RepositoryInvoker getInvokerFor(Class domainType) { - DynamicJpaRepository dynamicJpaRepository = (DynamicJpaRepository) repositories.getRepositoryFor(domainType); - RepositoryInvoker repositoryInvoker = delegate.getInvokerFor(domainType); - - return new DynamicRepositoryInvokerWrapper(dynamicJpaRepository, repositoryInvoker); - } +/* + * Copyright 2012-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.lightadmin.core.persistence.repository.invoker; + +import org.lightadmin.core.persistence.repository.DynamicJpaRepository; +import org.springframework.data.repository.support.Repositories; +import org.springframework.data.repository.support.RepositoryInvoker; +import org.springframework.data.repository.support.RepositoryInvokerFactory; + +public class DynamicRepositoryInvokerFactory implements RepositoryInvokerFactory { + + private final RepositoryInvokerFactory delegate; + private final Repositories repositories; + + public DynamicRepositoryInvokerFactory(Repositories repositories, RepositoryInvokerFactory repositoryInvokerFactory) { + this.repositories = repositories; + this.delegate = repositoryInvokerFactory; + } + + @Override + public RepositoryInvoker getInvokerFor(Class domainType) { + DynamicJpaRepository dynamicJpaRepository = (DynamicJpaRepository) repositories.getRepositoryFor(domainType); + RepositoryInvoker repositoryInvoker = delegate.getInvokerFor(domainType); + + return new DynamicRepositoryInvokerWrapper(dynamicJpaRepository, repositoryInvoker); + } } \ No newline at end of file diff --git a/lightadmin-core/src/main/java/org/lightadmin/core/persistence/repository/invoker/DynamicRepositoryInvokerWrapper.java b/lightadmin-core/src/main/java/org/lightadmin/core/persistence/repository/invoker/DynamicRepositoryInvokerWrapper.java index 75fe6f09..bd89b6f5 100644 --- a/lightadmin-core/src/main/java/org/lightadmin/core/persistence/repository/invoker/DynamicRepositoryInvokerWrapper.java +++ b/lightadmin-core/src/main/java/org/lightadmin/core/persistence/repository/invoker/DynamicRepositoryInvokerWrapper.java @@ -1,130 +1,117 @@ -/* - * Copyright 2012-2014 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.lightadmin.core.persistence.repository.invoker; - -import org.lightadmin.core.persistence.repository.DynamicJpaRepository; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Sort; -import org.springframework.data.jpa.domain.Specification; -import org.springframework.data.rest.core.invoke.RepositoryInvoker; - -import java.io.Serializable; -import java.lang.reflect.Method; -import java.util.List; -import java.util.Map; - -@SuppressWarnings("unchecked") -public class DynamicRepositoryInvokerWrapper implements DynamicRepositoryInvoker { - - private final DynamicJpaRepository repository; - private final RepositoryInvoker repositoryInvoker; - - public DynamicRepositoryInvokerWrapper(DynamicJpaRepository dynamicRepository, RepositoryInvoker repositoryInvoker) { - this.repository = dynamicRepository; - this.repositoryInvoker = repositoryInvoker; - } - - @Override - public Page findAll(Specification spec, Pageable pageable) { - return repository.findAll(spec, pageable); - } - - @Override - public List findAll(Specification spec, Sort sort) { - return repository.findAll(spec, sort); - } - - @Override - public List findAll(Specification spec) { - return repository.findAll(spec); - } - - @Override - public long count(Specification spec) { - return repository.count(spec); - } - - @Override - public T invokeSave(T object) { - return repositoryInvoker.invokeSave(object); - } - - @Override - public T invokeFindOne(Serializable id) { - return repositoryInvoker.invokeFindOne(id); - } - - @Override - public Iterable invokeFindAll(Pageable pageable) { - return repositoryInvoker.invokeFindAll(pageable); - } - - @Override - public Iterable invokeFindAll(Sort sort) { - return repositoryInvoker.invokeFindAll(sort); - } - - @Override - public void invokeDelete(Serializable serializable) { - repositoryInvoker.invokeDelete(serializable); - } - - @Override - public Object invokeQueryMethod(Method method, Map parameters, Pageable pageable, Sort sort) { - return repositoryInvoker.invokeQueryMethod(method, parameters, pageable, sort); - } - - @Override - public boolean hasSaveMethod() { - return repositoryInvoker.hasSaveMethod(); - } - - @Override - public boolean exposesSave() { - return repositoryInvoker.exposesSave(); - } - - @Override - public boolean hasDeleteMethod() { - return repositoryInvoker.hasDeleteMethod(); - } - - @Override - public boolean exposesDelete() { - return repositoryInvoker.exposesDelete(); - } - - @Override - public boolean hasFindOneMethod() { - return repositoryInvoker.hasFindOneMethod(); - } - - @Override - public boolean exposesFindOne() { - return repositoryInvoker.exposesFindOne(); - } - - @Override - public boolean hasFindAllMethod() { - return repositoryInvoker.hasFindAllMethod(); - } - - @Override - public boolean exposesFindAll() { - return repositoryInvoker.exposesFindAll(); - } +/* + * Copyright 2012-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.lightadmin.core.persistence.repository.invoker; + +import org.lightadmin.core.persistence.repository.DynamicJpaRepository; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; +import org.springframework.data.repository.support.RepositoryInvoker; +import org.springframework.util.MultiValueMap; + +import java.io.Serializable; +import java.lang.reflect.Method; +import java.util.List; +import java.util.Map; + +@SuppressWarnings("unchecked") +public class DynamicRepositoryInvokerWrapper implements DynamicRepositoryInvoker { + + private final DynamicJpaRepository repository; + private final RepositoryInvoker repositoryInvoker; + + public DynamicRepositoryInvokerWrapper(DynamicJpaRepository dynamicRepository, RepositoryInvoker repositoryInvoker) { + this.repository = dynamicRepository; + this.repositoryInvoker = repositoryInvoker; + } + + @Override + public Page findAll(Specification spec, Pageable pageable) { + return repository.findAll(spec, pageable); + } + + @Override + public List findAll(Specification spec, Sort sort) { + return repository.findAll(spec, sort); + } + + @Override + public List findAll(Specification spec) { + return repository.findAll(spec); + } + + @Override + public long count(Specification spec) { + return repository.count(spec); + } + + @Override + public T invokeSave(T object) { + return repositoryInvoker.invokeSave(object); + } + + @Override + public T invokeFindOne(Serializable id) { + return repositoryInvoker.invokeFindOne(id); + } + + @Override + public Iterable invokeFindAll(Pageable pageable) { + return repositoryInvoker.invokeFindAll(pageable); + } + + @Override + public Iterable invokeFindAll(Sort sort) { + return repositoryInvoker.invokeFindAll(sort); + } + + @Override + public void invokeDelete(Serializable serializable) { + repositoryInvoker.invokeDelete(serializable); + } + + @Override + public Object invokeQueryMethod(Method method, Map parameters, Pageable pageable, Sort sort) { + return repositoryInvoker.invokeQueryMethod(method, parameters, pageable, sort); + } + + @Override + public Object invokeQueryMethod(Method method, MultiValueMap parameters, + Pageable pageable, Sort sort) { + return repositoryInvoker.invokeQueryMethod(method, parameters, pageable, sort); + } + + @Override + public boolean hasSaveMethod() { + return repositoryInvoker.hasSaveMethod(); + } + + @Override + public boolean hasDeleteMethod() { + return repositoryInvoker.hasDeleteMethod(); + } + + @Override + public boolean hasFindOneMethod() { + return repositoryInvoker.hasFindOneMethod(); + } + + @Override + public boolean hasFindAllMethod() { + return repositoryInvoker.hasFindAllMethod(); + } } \ No newline at end of file diff --git a/lightadmin-core/src/main/java/org/lightadmin/core/web/RepositoryFilePropertyController.java b/lightadmin-core/src/main/java/org/lightadmin/core/web/RepositoryFilePropertyController.java index 4772104a..97af2c48 100644 --- a/lightadmin-core/src/main/java/org/lightadmin/core/web/RepositoryFilePropertyController.java +++ b/lightadmin-core/src/main/java/org/lightadmin/core/web/RepositoryFilePropertyController.java @@ -1,191 +1,191 @@ -/* - * Copyright 2012-2014 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.lightadmin.core.web; - -import org.lightadmin.core.storage.FileResourceStorage; -import org.lightadmin.core.web.support.DynamicRepositoryEntityLinks; -import org.lightadmin.core.web.support.FilePropertyValue; -import org.lightadmin.core.web.support.FileResourceLoader; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.mapping.PersistentEntity; -import org.springframework.data.mapping.PersistentProperty; -import org.springframework.data.rest.core.invoke.RepositoryInvoker; -import org.springframework.data.rest.webmvc.RepositoryRestController; -import org.springframework.data.rest.webmvc.ResourceNotFoundException; -import org.springframework.data.rest.webmvc.RootResourceInformation; -import org.springframework.data.rest.webmvc.support.BackendId; -import org.springframework.hateoas.Link; -import org.springframework.hateoas.Resource; -import org.springframework.hateoas.ResourceSupport; -import org.springframework.http.HttpHeaders; -import org.springframework.http.ResponseEntity; -import org.springframework.http.server.ServletServerHttpRequest; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.multipart.MultipartFile; -import org.springframework.web.multipart.MultipartHttpServletRequest; - -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.io.Serializable; -import java.util.Map; - -import static org.lightadmin.core.persistence.metamodel.PersistentPropertyType.isOfFileType; -import static org.springframework.data.rest.webmvc.ControllerUtils.toEmptyResponse; -import static org.springframework.data.rest.webmvc.ControllerUtils.toResponseEntity; -import static org.springframework.http.HttpStatus.METHOD_NOT_ALLOWED; -import static org.springframework.http.HttpStatus.OK; -import static org.springframework.web.bind.annotation.RequestMethod.*; - -@RepositoryRestController -public class RepositoryFilePropertyController { - - private static final String BASE_MAPPING = "/{repository}/{id}/{property}"; - - private BeanFactory beanFactory; - - @Autowired - public RepositoryFilePropertyController(BeanFactory beanFactory) { - this.beanFactory = beanFactory; - } - - @RequestMapping(value = BASE_MAPPING + "/file", method = GET) - public void filePropertyOfEntity(RootResourceInformation repoRequest, ServletResponse response, @BackendId Serializable id, @PathVariable String property) throws Exception { - PersistentEntity persistentEntity = repoRequest.getPersistentEntity(); - RepositoryInvoker invoker = repoRequest.getInvoker(); - - Object domainObj = invoker.invokeFindOne(id); - - if (null == domainObj) { - throw new ResourceNotFoundException(); - } - - PersistentProperty prop = persistentEntity.getPersistentProperty(property); - if (null == prop) { - throw new ResourceNotFoundException(); - } - - if (isOfFileType(prop)) { - fileResourceLoader().downloadFile(domainObj, prop, (HttpServletResponse) response); - } - } - - @RequestMapping(value = BASE_MAPPING + "/binary", method = GET) - public ResponseEntity filePropertyValueOfEntity(RootResourceInformation repoRequest, @BackendId Serializable id, @PathVariable String property) throws Exception { - PersistentEntity persistentEntity = repoRequest.getPersistentEntity(); - RepositoryInvoker invoker = repoRequest.getInvoker(); - - Object domainObj = invoker.invokeFindOne(id); - - if (null == domainObj) { - throw new ResourceNotFoundException(); - } - - PersistentProperty prop = persistentEntity.getPersistentProperty(property); - if (null == prop) { - throw new ResourceNotFoundException(); - } - - if (isOfFileType(prop)) { - return toResponseEntity(OK, new HttpHeaders(), new Resource(evaluateFilePropertyValue(domainObj, prop))); - } - - return toEmptyResponse(METHOD_NOT_ALLOWED); - } - - @RequestMapping(value = BASE_MAPPING + "/file", method = DELETE) - public ResponseEntity deleteFileOfPropertyOfEntity(RootResourceInformation repoRequest, @BackendId Serializable id, @PathVariable String property) throws Exception { - PersistentEntity persistentEntity = repoRequest.getPersistentEntity(); - RepositoryInvoker invoker = repoRequest.getInvoker(); - - Object domainObj = invoker.invokeFindOne(id); - - if (null == domainObj) { - throw new ResourceNotFoundException(); - } - - PersistentProperty prop = persistentEntity.getPersistentProperty(property); - if (null == prop) { - throw new ResourceNotFoundException(); - } - - if (!isOfFileType(prop)) { - return toEmptyResponse(METHOD_NOT_ALLOWED); - } - - fileResourceStorage().delete(domainObj, prop); - - invoker.invokeSave(domainObj); - - return toEmptyResponse(OK); - } - - @RequestMapping(value = BASE_MAPPING + "/file", method = {POST}) - public ResponseEntity saveFilePropertyOfEntity(final ServletServerHttpRequest request) throws Exception { - final MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest) request.getServletRequest(); - - final Map fileMap = multipartHttpServletRequest.getFileMap(); - - if (!fileMap.isEmpty()) { - final Map.Entry fileEntry = fileMap.entrySet().iterator().next(); - - return toResponseEntity(OK, new HttpHeaders(), fileResource(fileEntry)); - } - - return toEmptyResponse(METHOD_NOT_ALLOWED); - } - - private FilePropertyValue evaluateFilePropertyValue(Object instance, PersistentProperty persistentProperty) { - FileResourceStorage fileResourceStorage = fileResourceStorage(); - - try { - if (!fileResourceStorage.fileExists(instance, persistentProperty)) { - return new FilePropertyValue(false); - } - - Link fileLink = entityLinks().linkForFilePropertyLink(instance, persistentProperty); - - byte[] fileData = fileResourceStorage.load(instance, persistentProperty); - - return new FilePropertyValue(fileLink, fileData); - - } catch (Exception e) { - throw new ResourceNotFoundException(e.getMessage()); - } - } - - private Resource fileResource(Map.Entry fileEntry) throws IOException { - MultipartFile multipartFile = fileEntry.getValue(); - - FilePropertyValue filePropertyValue = new FilePropertyValue(multipartFile.getOriginalFilename(), multipartFile.getBytes()); - - return new Resource(filePropertyValue); - } - - private FileResourceLoader fileResourceLoader() { - return beanFactory.getBean(FileResourceLoader.class); - } - - private FileResourceStorage fileResourceStorage() { - return beanFactory.getBean(FileResourceStorage.class); - } - - private DynamicRepositoryEntityLinks entityLinks() { - return beanFactory.getBean(DynamicRepositoryEntityLinks.class); - } +/* + * Copyright 2012-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.lightadmin.core.web; + +import org.lightadmin.core.storage.FileResourceStorage; +import org.lightadmin.core.web.support.DynamicRepositoryEntityLinks; +import org.lightadmin.core.web.support.FilePropertyValue; +import org.lightadmin.core.web.support.FileResourceLoader; +import org.springframework.beans.factory.BeanFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mapping.PersistentEntity; +import org.springframework.data.mapping.PersistentProperty; +import org.springframework.data.repository.support.RepositoryInvoker; +import org.springframework.data.rest.webmvc.RepositoryRestController; +import org.springframework.data.rest.webmvc.ResourceNotFoundException; +import org.springframework.data.rest.webmvc.RootResourceInformation; +import org.springframework.data.rest.webmvc.support.BackendId; +import org.springframework.hateoas.Link; +import org.springframework.hateoas.Resource; +import org.springframework.hateoas.ResourceSupport; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseEntity; +import org.springframework.http.server.ServletServerHttpRequest; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.multipart.MultipartFile; +import org.springframework.web.multipart.MultipartHttpServletRequest; + +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.io.Serializable; +import java.util.Map; + +import static org.lightadmin.core.persistence.metamodel.PersistentPropertyType.isOfFileType; +import static org.springframework.data.rest.webmvc.ControllerUtils.toEmptyResponse; +import static org.springframework.data.rest.webmvc.ControllerUtils.toResponseEntity; +import static org.springframework.http.HttpStatus.METHOD_NOT_ALLOWED; +import static org.springframework.http.HttpStatus.OK; +import static org.springframework.web.bind.annotation.RequestMethod.*; + +@RepositoryRestController +public class RepositoryFilePropertyController { + + private static final String BASE_MAPPING = "/{repository}/{id}/{property}"; + + private BeanFactory beanFactory; + + @Autowired + public RepositoryFilePropertyController(BeanFactory beanFactory) { + this.beanFactory = beanFactory; + } + + @RequestMapping(value = BASE_MAPPING + "/file", method = GET) + public void filePropertyOfEntity(RootResourceInformation repoRequest, ServletResponse response, @BackendId Serializable id, @PathVariable String property) throws Exception { + PersistentEntity persistentEntity = repoRequest.getPersistentEntity(); + RepositoryInvoker invoker = repoRequest.getInvoker(); + + Object domainObj = invoker.invokeFindOne(id); + + if (null == domainObj) { + throw new ResourceNotFoundException(); + } + + PersistentProperty prop = persistentEntity.getPersistentProperty(property); + if (null == prop) { + throw new ResourceNotFoundException(); + } + + if (isOfFileType(prop)) { + fileResourceLoader().downloadFile(domainObj, prop, (HttpServletResponse) response); + } + } + + @RequestMapping(value = BASE_MAPPING + "/binary", method = GET) + public ResponseEntity filePropertyValueOfEntity(RootResourceInformation repoRequest, @BackendId Serializable id, @PathVariable String property) throws Exception { + PersistentEntity persistentEntity = repoRequest.getPersistentEntity(); + RepositoryInvoker invoker = repoRequest.getInvoker(); + + Object domainObj = invoker.invokeFindOne(id); + + if (null == domainObj) { + throw new ResourceNotFoundException(); + } + + PersistentProperty prop = persistentEntity.getPersistentProperty(property); + if (null == prop) { + throw new ResourceNotFoundException(); + } + + if (isOfFileType(prop)) { + return toResponseEntity(OK, new HttpHeaders(), new Resource(evaluateFilePropertyValue(domainObj, prop))); + } + + return toEmptyResponse(METHOD_NOT_ALLOWED); + } + + @RequestMapping(value = BASE_MAPPING + "/file", method = DELETE) + public ResponseEntity deleteFileOfPropertyOfEntity(RootResourceInformation repoRequest, @BackendId Serializable id, @PathVariable String property) throws Exception { + PersistentEntity persistentEntity = repoRequest.getPersistentEntity(); + RepositoryInvoker invoker = repoRequest.getInvoker(); + + Object domainObj = invoker.invokeFindOne(id); + + if (null == domainObj) { + throw new ResourceNotFoundException(); + } + + PersistentProperty prop = persistentEntity.getPersistentProperty(property); + if (null == prop) { + throw new ResourceNotFoundException(); + } + + if (!isOfFileType(prop)) { + return toEmptyResponse(METHOD_NOT_ALLOWED); + } + + fileResourceStorage().delete(domainObj, prop); + + invoker.invokeSave(domainObj); + + return toEmptyResponse(OK); + } + + @RequestMapping(value = BASE_MAPPING + "/file", method = {POST}) + public ResponseEntity saveFilePropertyOfEntity(final ServletServerHttpRequest request) throws Exception { + final MultipartHttpServletRequest multipartHttpServletRequest = (MultipartHttpServletRequest) request.getServletRequest(); + + final Map fileMap = multipartHttpServletRequest.getFileMap(); + + if (!fileMap.isEmpty()) { + final Map.Entry fileEntry = fileMap.entrySet().iterator().next(); + + return toResponseEntity(OK, new HttpHeaders(), fileResource(fileEntry)); + } + + return toEmptyResponse(METHOD_NOT_ALLOWED); + } + + private FilePropertyValue evaluateFilePropertyValue(Object instance, PersistentProperty persistentProperty) { + FileResourceStorage fileResourceStorage = fileResourceStorage(); + + try { + if (!fileResourceStorage.fileExists(instance, persistentProperty)) { + return new FilePropertyValue(false); + } + + Link fileLink = entityLinks().linkForFilePropertyLink(instance, persistentProperty); + + byte[] fileData = fileResourceStorage.load(instance, persistentProperty); + + return new FilePropertyValue(fileLink, fileData); + + } catch (Exception e) { + throw new ResourceNotFoundException(e.getMessage()); + } + } + + private Resource fileResource(Map.Entry fileEntry) throws IOException { + MultipartFile multipartFile = fileEntry.getValue(); + + FilePropertyValue filePropertyValue = new FilePropertyValue(multipartFile.getOriginalFilename(), multipartFile.getBytes()); + + return new Resource(filePropertyValue); + } + + private FileResourceLoader fileResourceLoader() { + return beanFactory.getBean(FileResourceLoader.class); + } + + private FileResourceStorage fileResourceStorage() { + return beanFactory.getBean(FileResourceStorage.class); + } + + private DynamicRepositoryEntityLinks entityLinks() { + return beanFactory.getBean(DynamicRepositoryEntityLinks.class); + } } \ No newline at end of file diff --git a/lightadmin-core/src/main/java/org/lightadmin/core/web/support/DynamicPersistentEntityResourceAssembler.java b/lightadmin-core/src/main/java/org/lightadmin/core/web/support/DynamicPersistentEntityResourceAssembler.java deleted file mode 100644 index 827b5158..00000000 --- a/lightadmin-core/src/main/java/org/lightadmin/core/web/support/DynamicPersistentEntityResourceAssembler.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2012-2014 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.lightadmin.core.web.support; - -import org.springframework.data.mapping.PersistentEntity; -import org.springframework.data.repository.core.EntityInformation; -import org.springframework.data.repository.support.Repositories; -import org.springframework.data.rest.core.mapping.ResourceMappings; -import org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler; -import org.springframework.data.rest.webmvc.support.Projector; -import org.springframework.hateoas.EntityLinks; -import org.springframework.hateoas.Link; -import org.springframework.util.Assert; - -import java.io.Serializable; - -import static org.springframework.beans.PropertyAccessorFactory.forDirectFieldAccess; - -/** - * Fix of Spring Data REST related defect - * - * @author Maxim Kharchenko (kharchenko.max@gmail.com) - */ -public class DynamicPersistentEntityResourceAssembler extends PersistentEntityResourceAssembler { - - public DynamicPersistentEntityResourceAssembler(PersistentEntityResourceAssembler resourceAssembler) { - super(repositories(resourceAssembler), entityLinks(resourceAssembler), projector(resourceAssembler), mappings(resourceAssembler)); - } - - /** - * @see DATAREST-269 (https://jira.spring.io/browse/DATAREST-269) - */ - @Override - public Link getSelfLinkFor(Object instance) { - Assert.notNull(instance, "Domain object must not be null!"); - - Repositories repositories = repositories(this); - - Class instanceType = instance.getClass(); - PersistentEntity entity = repositories.getPersistentEntity(instanceType); - - if (entity == null) { - throw new IllegalArgumentException(String.format("Cannot create self link for %s! No persistent entity found!", instanceType)); - } - - EntityInformation entityInformation = repositories.getEntityInformationFor(instanceType); - Serializable id = entityInformation.getId(instance); - - if (id == null) { - return entityLinks(this).linkToCollectionResource(entity.getType()).withSelfRel(); - } - - return entityLinks(this).linkToSingleResource(entity.getType(), id).withSelfRel(); - } - - private static Repositories repositories(PersistentEntityResourceAssembler persistentEntityResourceAssembler) { - return (Repositories) forDirectFieldAccess(persistentEntityResourceAssembler).getPropertyValue("repositories"); - } - - private static EntityLinks entityLinks(PersistentEntityResourceAssembler persistentEntityResourceAssembler) { - return (EntityLinks) forDirectFieldAccess(persistentEntityResourceAssembler).getPropertyValue("entityLinks"); - } - - private static Projector projector(PersistentEntityResourceAssembler persistentEntityResourceAssembler) { - return (Projector) forDirectFieldAccess(persistentEntityResourceAssembler).getPropertyValue("projector"); - } - - private static ResourceMappings mappings(PersistentEntityResourceAssembler persistentEntityResourceAssembler) { - return (ResourceMappings) forDirectFieldAccess(persistentEntityResourceAssembler).getPropertyValue("mappings"); - } -} \ No newline at end of file diff --git a/lightadmin-core/src/main/java/org/lightadmin/core/web/support/DynamicPersistentEntityResourceAssemblerArgumentResolver.java b/lightadmin-core/src/main/java/org/lightadmin/core/web/support/DynamicPersistentEntityResourceAssemblerArgumentResolver.java deleted file mode 100644 index d23345b6..00000000 --- a/lightadmin-core/src/main/java/org/lightadmin/core/web/support/DynamicPersistentEntityResourceAssemblerArgumentResolver.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright 2012-2014 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.lightadmin.core.web.support; - -import org.springframework.core.MethodParameter; -import org.springframework.data.rest.webmvc.PersistentEntityResourceAssembler; -import org.springframework.data.rest.webmvc.config.PersistentEntityResourceAssemblerArgumentResolver; -import org.springframework.web.bind.support.WebDataBinderFactory; -import org.springframework.web.context.request.NativeWebRequest; -import org.springframework.web.method.support.HandlerMethodArgumentResolver; -import org.springframework.web.method.support.ModelAndViewContainer; - -/** - * @author Maxim Kharchenko (kharchenko.max@gmail.com) - */ -public class DynamicPersistentEntityResourceAssemblerArgumentResolver implements HandlerMethodArgumentResolver { - - private PersistentEntityResourceAssemblerArgumentResolver delegate; - - public DynamicPersistentEntityResourceAssemblerArgumentResolver(PersistentEntityResourceAssemblerArgumentResolver delegate) { - this.delegate = delegate; - } - - @Override - public boolean supportsParameter(MethodParameter parameter) { - return this.delegate.supportsParameter(parameter); - } - - @Override - public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { - PersistentEntityResourceAssembler persistentEntityResourceAssembler = (PersistentEntityResourceAssembler) delegate.resolveArgument(parameter, mavContainer, webRequest, binderFactory); - - return new DynamicPersistentEntityResourceAssembler(persistentEntityResourceAssembler); - } -} \ No newline at end of file diff --git a/lightadmin-core/src/main/java/org/lightadmin/core/web/support/DynamicPersistentEntityResourceProcessor.java b/lightadmin-core/src/main/java/org/lightadmin/core/web/support/DynamicPersistentEntityResourceProcessor.java index 2ee1616f..dee14a98 100644 --- a/lightadmin-core/src/main/java/org/lightadmin/core/web/support/DynamicPersistentEntityResourceProcessor.java +++ b/lightadmin-core/src/main/java/org/lightadmin/core/web/support/DynamicPersistentEntityResourceProcessor.java @@ -1,305 +1,245 @@ -/* - * Copyright 2012-2014 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.lightadmin.core.web.support; - -import com.fasterxml.jackson.annotation.JsonInclude; -import com.fasterxml.jackson.annotation.JsonProperty; -import org.lightadmin.api.config.utils.EntityNameExtractor; -import org.lightadmin.core.config.domain.DomainTypeAdministrationConfiguration; -import org.lightadmin.core.config.domain.DomainTypeBasicConfiguration; -import org.lightadmin.core.config.domain.GlobalAdministrationConfiguration; -import org.lightadmin.core.config.domain.field.FieldMetadata; -import org.lightadmin.core.config.domain.unit.DomainConfigurationUnitType; -import org.lightadmin.core.persistence.metamodel.PersistentPropertyType; -import org.lightadmin.core.storage.FileResourceStorage; -import org.springframework.data.mapping.*; -import org.springframework.data.rest.core.mapping.ResourceMappings; -import org.springframework.data.rest.webmvc.PersistentEntityResource; -import org.springframework.data.rest.webmvc.mapping.AssociationLinks; -import org.springframework.data.util.DirectFieldAccessFallbackBeanWrapper; -import org.springframework.hateoas.Link; -import org.springframework.hateoas.ResourceProcessor; - -import java.util.Collections; -import java.util.List; -import java.util.Map; - -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; -import static com.google.common.collect.Lists.newArrayList; -import static com.google.common.collect.Maps.newHashMap; -import static com.google.common.collect.Maps.newLinkedHashMap; -import static org.lightadmin.core.config.domain.configuration.support.ExceptionAwareTransformer.exceptionAwareNameExtractor; -import static org.lightadmin.core.config.domain.field.FieldMetadataUtils.customFields; -import static org.lightadmin.core.config.domain.field.FieldMetadataUtils.transientFields; -import static org.lightadmin.core.config.domain.unit.DomainConfigurationUnitType.*; -import static org.lightadmin.core.persistence.metamodel.PersistentPropertyType.FILE; -import static org.lightadmin.core.web.support.DynamicPersistentEntityResourceProcessor.PersistentEntityWrapper.persistentEntity; - -@SuppressWarnings(value = {"unchecked", "unused"}) -public class DynamicPersistentEntityResourceProcessor implements ResourceProcessor { - - private final GlobalAdministrationConfiguration adminConfiguration; - private final DynamicRepositoryEntityLinks entityLinks; - private final DomainEntityLinks domainEntityLinks; - private final FileResourceStorage fileResourceStorage; - private final AssociationLinks associationLinks; - - public DynamicPersistentEntityResourceProcessor(GlobalAdministrationConfiguration adminConfiguration, FileResourceStorage fileResourceStorage, DynamicRepositoryEntityLinks entityLinks, DomainEntityLinks domainEntityLinks, ResourceMappings resourceMappings) { - this.adminConfiguration = adminConfiguration; - this.domainEntityLinks = domainEntityLinks; - this.entityLinks = entityLinks; - this.fileResourceStorage = fileResourceStorage; - this.associationLinks = new AssociationLinks(resourceMappings); - } - - @Override - public PersistentEntityResource process(PersistentEntityResource persistentEntityResource) { - PersistentEntity persistentEntity = persistentEntityResource.getPersistentEntity(); - Object value = persistentEntityResource.getContent(); - Link[] links = persistentEntityResource.getLinks().toArray(new Link[persistentEntityResource.getLinks().size()]); - - String stringRepresentation = stringRepresentation(value, persistentEntity); - Link domainLink = domainLink(persistentEntityResource); - boolean managedDomainType = adminConfiguration.isManagedDomainType(persistentEntity.getType()); - String primaryKey = primaryKey(persistentEntity); - - Map> dynamicProperties = dynamicPropertiesPerUnit(value, persistentEntity); - - PersistentEntityWrapper persistentEntityWrapper = persistentEntity(value, dynamicProperties, stringRepresentation, domainLink, managedDomainType, primaryKey); - - PersistentEntityResource.Builder builder = PersistentEntityResource.build(persistentEntityWrapper, persistentEntity); - for (Link link: links) { - builder = builder.withLink(link); - } - return builder.build(); - } - - private String primaryKey(PersistentEntity persistentEntity) { - return persistentEntity.getIdProperty().getName(); - } - - private String stringRepresentation(Object value, PersistentEntity persistentEntity) { - DomainTypeBasicConfiguration domainTypeBasicConfiguration = adminConfiguration.forDomainType(persistentEntity.getType()); - EntityNameExtractor nameExtractor = domainTypeBasicConfiguration.getEntityConfiguration().getNameExtractor(); - - return exceptionAwareNameExtractor(nameExtractor, domainTypeBasicConfiguration).apply(value); - } - - private Link domainLink(PersistentEntityResource persistentEntityResource) { - PersistentEntity persistentEntity = persistentEntityResource.getPersistentEntity(); - if (domainEntityLinks.supports(persistentEntity.getType())) { - return domainEntityLinks.linkFor(persistentEntityResource); - } - return null; - } - - private Map> dynamicPropertiesPerUnit(Object value, PersistentEntity persistentEntity) { - if (!adminConfiguration.isManagedDomainType(persistentEntity.getType())) { - return Collections.emptyMap(); - } - - DomainTypeAdministrationConfiguration managedDomainTypeConfiguration = adminConfiguration.forManagedDomainType(persistentEntity.getType()); - - List units = newArrayList(LIST_VIEW, FORM_VIEW, SHOW_VIEW, QUICK_VIEW); - - List persistentProperties = findPersistentFileProperties(persistentEntity); - List associations = findLinkableAssociations(persistentEntity); - - Map> dynamicPropertiesPerUnit = newHashMap(); - for (DomainConfigurationUnitType unit : units) { - Map dynamicProperties = newLinkedHashMap(); - for (PersistentProperty persistentProperty : persistentProperties) { - dynamicProperties.put(persistentProperty.getName(), filePropertyValue(persistentProperty, value)); - } - for (Association association : associations) { - dynamicProperties.put(association.getInverse().getName(), associationPropertyValue(association, value)); - } - for (FieldMetadata customField : customFields(managedDomainTypeConfiguration.fieldsForUnit(unit))) { - dynamicProperties.put(customField.getUuid(), customField.getValue(value)); - } - for (FieldMetadata transientField : transientFields(managedDomainTypeConfiguration.fieldsForUnit(unit))) { - dynamicProperties.put(transientField.getUuid(), transientField.getValue(value)); - } - dynamicPropertiesPerUnit.put(unit, dynamicProperties); - } - return dynamicPropertiesPerUnit; - } - - private Object associationPropertyValue(Association association, Object instance) { - PersistentProperty persistentProperty = association.getInverse(); - PersistentEntity persistentEntity = persistentProperty.getOwner(); - - if (persistentProperty.isMap()) { - return null; - } - - if (persistentProperty.isCollectionLike()) { - return associatedPersistentEntities(association, instance); - } - - Object associationValue = beanWrapper(instance).getPropertyValue(persistentProperty.getName()); - - return associatedPersistentEntity(persistentProperty, associationValue); - } - - private List associatedPersistentEntities(Association association, Object instance) { - PersistentProperty persistentProperty = association.getInverse(); - - Object associationValue = beanWrapper(instance).getPropertyValue(persistentProperty.getName()); - if (associationValue == null) { - return null; - } - - List result = newArrayList(); - - if (persistentProperty.isArray()) { - for (Object item : (Object[]) associationValue) { - result.add(associatedPersistentEntity(persistentProperty, item)); - } - return result; - } - - for (Object item : (Iterable) associationValue) { - result.add(associatedPersistentEntity(persistentProperty, item)); - } - return result; - } - - private PersistentEntityWrapper associatedPersistentEntity(PersistentProperty persistentProperty, Object associationValue) { - if (associationValue == null) { - return null; - } - - Class associationType = persistentProperty.getActualType(); - boolean managedDomainType = adminConfiguration.isManagedDomainType(associationType); - PersistentEntity associationPersistentEntity = adminConfiguration.forDomainType(associationType).getPersistentEntity(); - - String stringRepresentation = stringRepresentation(associationValue, associationPersistentEntity); - String primaryKey = primaryKey(associationPersistentEntity); - Object primaryKeyValue = beanWrapper(associationValue).getPropertyValue(primaryKey); - - Link domainLink = null; - if (domainEntityLinks.supports(associationType)) { - domainLink = domainEntityLinks.linkToSingleResource(associationType, primaryKeyValue); - } - - return PersistentEntityWrapper.associatedPersistentEntity(stringRepresentation, managedDomainType, primaryKey, primaryKeyValue, domainLink); - } - - private static DirectFieldAccessFallbackBeanWrapper beanWrapper(Object instance) { - return new DirectFieldAccessFallbackBeanWrapper(instance); - } - - private List findPersistentFileProperties(PersistentEntity persistentEntity) { - final List result = newArrayList(); - persistentEntity.doWithProperties(new SimplePropertyHandler() { - @Override - public void doWithPersistentProperty(PersistentProperty property) { - if (PersistentPropertyType.forPersistentProperty(property) == FILE) { - result.add(property); - } - } - }); - return result; - } - - private List findLinkableAssociations(PersistentEntity persistentEntity) { - final List result = newArrayList(); - persistentEntity.doWithAssociations(new SimpleAssociationHandler() { - @Override - public void doWithAssociation(Association> association) { - if (associationLinks.isLinkableAssociation(association.getInverse())) { - result.add(association); - } - } - }); - return result; - } - - private FilePropertyValue filePropertyValue(PersistentProperty persistentProperty, Object value) { - try { - if (!fileResourceStorage.fileExists(value, persistentProperty)) { - return new FilePropertyValue(false); - } - return new FilePropertyValue(entityLinks.linkForFilePropertyLink(value, persistentProperty)); - } catch (Exception e) { - return null; - } - } - - static class PersistentEntityWrapper { - private String stringRepresentation; - private boolean managedDomainType; - private String primaryKey; - private Link domainLink; - private Object persistentEntity; - private Map> dynamicProperties; - - private PersistentEntityWrapper(Object persistentEntity, Map> dynamicProperties, String stringRepresentation, Link domainLink, boolean managedDomainType, String primaryKey) { - this.stringRepresentation = stringRepresentation; - this.domainLink = domainLink; - this.managedDomainType = managedDomainType; - this.persistentEntity = persistentEntity; - this.dynamicProperties = dynamicProperties; - this.primaryKey = primaryKey; - } - - public static PersistentEntityWrapper associatedPersistentEntity(String stringRepresentation, boolean managedDomainType, String primaryKey, Object primaryKeyValue, Link domainLink) { - Map persistentEntity = newHashMap(); - persistentEntity.put(primaryKey, primaryKeyValue); - - return new PersistentEntityWrapper(persistentEntity, null, stringRepresentation, domainLink, managedDomainType, primaryKey); - } - - public static PersistentEntityWrapper persistentEntity(Object instance, Map> dynamicProperties, String stringRepresentation, Link domainLink, boolean managedDomainType, String primaryKey) { - return new PersistentEntityWrapper(instance, dynamicProperties, stringRepresentation, domainLink, managedDomainType, primaryKey); - } - - @JsonProperty("string_representation") - public String getStringRepresentation() { - return stringRepresentation; - } - - @JsonProperty("primary_key") - public String getPrimaryKey() { - return primaryKey; - } - - @JsonProperty("managed_type") - public boolean isManagedDomainType() { - return managedDomainType; - } - - @JsonProperty("domain_link") - @JsonInclude(NON_NULL) - public Link getDomainLink() { - return domainLink; - } - - @JsonProperty("original_properties") - @JsonInclude(NON_NULL) - public Object getPersistentEntity() { - return persistentEntity; - } - - @JsonProperty("dynamic_properties") - @JsonInclude(NON_EMPTY) - public Map> getDynamicProperties() { - return dynamicProperties; - } - } +/* + * Copyright 2012-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.lightadmin.core.web.support; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.lightadmin.api.config.utils.EntityNameExtractor; +import org.lightadmin.core.config.domain.DomainTypeAdministrationConfiguration; +import org.lightadmin.core.config.domain.DomainTypeBasicConfiguration; +import org.lightadmin.core.config.domain.GlobalAdministrationConfiguration; +import org.lightadmin.core.config.domain.field.FieldMetadata; +import org.lightadmin.core.config.domain.unit.DomainConfigurationUnitType; +import org.lightadmin.core.persistence.metamodel.PersistentPropertyType; +import org.lightadmin.core.storage.FileResourceStorage; +import org.springframework.data.mapping.*; +import org.springframework.data.rest.core.config.RepositoryRestConfiguration; +import org.springframework.data.rest.core.mapping.ResourceMappings; +import org.springframework.data.rest.webmvc.PersistentEntityResource; +import org.springframework.data.rest.webmvc.mapping.Associations; +import org.springframework.data.util.DirectFieldAccessFallbackBeanWrapper; +import org.springframework.hateoas.Link; +import org.springframework.hateoas.ResourceProcessor; + +import java.util.Collections; +import java.util.List; +import java.util.Map; + +import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; +import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; +import static com.google.common.collect.Lists.newArrayList; +import static com.google.common.collect.Maps.newHashMap; +import static com.google.common.collect.Maps.newLinkedHashMap; +import static org.lightadmin.core.config.domain.configuration.support.ExceptionAwareTransformer.exceptionAwareNameExtractor; +import static org.lightadmin.core.config.domain.field.FieldMetadataUtils.customFields; +import static org.lightadmin.core.config.domain.field.FieldMetadataUtils.transientFields; +import static org.lightadmin.core.config.domain.unit.DomainConfigurationUnitType.*; +import static org.lightadmin.core.persistence.metamodel.PersistentPropertyType.FILE; + +@SuppressWarnings(value = {"unchecked", "unused"}) +public class DynamicPersistentEntityResourceProcessor implements ResourceProcessor { + + private final GlobalAdministrationConfiguration adminConfiguration; + private final DynamicRepositoryEntityLinks entityLinks; + private final DomainEntityLinks domainEntityLinks; + private final FileResourceStorage fileResourceStorage; + private Associations associations; + + public DynamicPersistentEntityResourceProcessor(GlobalAdministrationConfiguration adminConfiguration, + FileResourceStorage fileResourceStorage, DynamicRepositoryEntityLinks entityLinks, + DomainEntityLinks domainEntityLinks, ResourceMappings resourceMappings, Associations associations) { + this.adminConfiguration = adminConfiguration; + this.domainEntityLinks = domainEntityLinks; + this.entityLinks = entityLinks; + this.fileResourceStorage = fileResourceStorage; + this.associations = associations; + } + + @Override + public PersistentEntityResource process(PersistentEntityResource persistentEntityResource) { + PersistentEntity persistentEntity = persistentEntityResource.getPersistentEntity(); + Object value = persistentEntityResource.getContent(); + Link[] links = persistentEntityResource.getLinks().toArray(new Link[persistentEntityResource.getLinks().size()]); + + String stringRepresentation = stringRepresentation(value, persistentEntity); + Link domainLink = domainLink(persistentEntityResource); + boolean managedDomainType = adminConfiguration.isManagedDomainType(persistentEntity.getType()); + String primaryKey = primaryKey(persistentEntity); + + Map> dynamicProperties = dynamicPropertiesPerUnit(value, persistentEntity); + + PersistentEntityWrapper persistentEntityWrapper = PersistentEntityWrapper.persistentEntity(value, dynamicProperties, stringRepresentation, domainLink, managedDomainType, primaryKey); + + PersistentEntityResource.Builder builder = PersistentEntityResource.build(persistentEntityWrapper, persistentEntity); + for (Link link: links) { + builder = builder.withLink(link); + } + return builder.build(); + } + + private String primaryKey(PersistentEntity persistentEntity) { + return persistentEntity.getIdProperty().getName(); + } + + private String stringRepresentation(Object value, PersistentEntity persistentEntity) { + DomainTypeBasicConfiguration domainTypeBasicConfiguration = adminConfiguration.forDomainType(persistentEntity.getType()); + EntityNameExtractor nameExtractor = domainTypeBasicConfiguration.getEntityConfiguration().getNameExtractor(); + + return exceptionAwareNameExtractor(nameExtractor, domainTypeBasicConfiguration).apply(value); + } + + private Link domainLink(PersistentEntityResource persistentEntityResource) { + PersistentEntity persistentEntity = persistentEntityResource.getPersistentEntity(); + if (domainEntityLinks.supports(persistentEntity.getType())) { + return domainEntityLinks.linkFor(persistentEntityResource); + } + return null; + } + + private Map> dynamicPropertiesPerUnit(Object value, PersistentEntity persistentEntity) { + if (!adminConfiguration.isManagedDomainType(persistentEntity.getType())) { + return Collections.emptyMap(); + } + + DomainTypeAdministrationConfiguration managedDomainTypeConfiguration = adminConfiguration.forManagedDomainType(persistentEntity.getType()); + + List units = newArrayList(LIST_VIEW, FORM_VIEW, SHOW_VIEW, QUICK_VIEW); + + List persistentProperties = findPersistentFileProperties(persistentEntity); + List associations = findLinkableAssociations(persistentEntity); + + Map> dynamicPropertiesPerUnit = newHashMap(); + for (DomainConfigurationUnitType unit : units) { + Map dynamicProperties = newLinkedHashMap(); + for (PersistentProperty persistentProperty : persistentProperties) { + dynamicProperties.put(persistentProperty.getName(), filePropertyValue(persistentProperty, value)); + } + for (Association association : associations) { + dynamicProperties.put(association.getInverse().getName(), associationPropertyValue(association, value)); + } + for (FieldMetadata customField : customFields(managedDomainTypeConfiguration.fieldsForUnit(unit))) { + dynamicProperties.put(customField.getUuid(), customField.getValue(value)); + } + for (FieldMetadata transientField : transientFields(managedDomainTypeConfiguration.fieldsForUnit(unit))) { + dynamicProperties.put(transientField.getUuid(), transientField.getValue(value)); + } + dynamicPropertiesPerUnit.put(unit, dynamicProperties); + } + return dynamicPropertiesPerUnit; + } + + private Object associationPropertyValue(Association association, Object instance) { + PersistentProperty persistentProperty = association.getInverse(); + PersistentEntity persistentEntity = persistentProperty.getOwner(); + + if (persistentProperty.isMap()) { + return null; + } + + if (persistentProperty.isCollectionLike()) { + return associatedPersistentEntities(association, instance); + } + + Object associationValue = beanWrapper(instance).getPropertyValue(persistentProperty.getName()); + + return associatedPersistentEntity(persistentProperty, associationValue); + } + + private List associatedPersistentEntities(Association association, Object instance) { + PersistentProperty persistentProperty = association.getInverse(); + + Object associationValue = beanWrapper(instance).getPropertyValue(persistentProperty.getName()); + if (associationValue == null) { + return null; + } + + List result = newArrayList(); + + if (persistentProperty.isArray()) { + for (Object item : (Object[]) associationValue) { + result.add(associatedPersistentEntity(persistentProperty, item)); + } + return result; + } + + for (Object item : (Iterable) associationValue) { + result.add(associatedPersistentEntity(persistentProperty, item)); + } + return result; + } + + private PersistentEntityWrapper associatedPersistentEntity(PersistentProperty persistentProperty, Object associationValue) { + if (associationValue == null) { + return null; + } + + Class associationType = persistentProperty.getActualType(); + boolean managedDomainType = adminConfiguration.isManagedDomainType(associationType); + PersistentEntity associationPersistentEntity = adminConfiguration.forDomainType(associationType).getPersistentEntity(); + + String stringRepresentation = stringRepresentation(associationValue, associationPersistentEntity); + String primaryKey = primaryKey(associationPersistentEntity); + Object primaryKeyValue = beanWrapper(associationValue).getPropertyValue(primaryKey); + + Link domainLink = null; + if (domainEntityLinks.supports(associationType)) { + domainLink = domainEntityLinks.linkToSingleResource(associationType, primaryKeyValue); + } + + return PersistentEntityWrapper.associatedPersistentEntity(stringRepresentation, managedDomainType, primaryKey, primaryKeyValue, domainLink); + } + + private static DirectFieldAccessFallbackBeanWrapper beanWrapper(Object instance) { + return new DirectFieldAccessFallbackBeanWrapper(instance); + } + + private List findPersistentFileProperties(PersistentEntity persistentEntity) { + final List result = newArrayList(); + persistentEntity.doWithProperties(new SimplePropertyHandler() { + @Override + public void doWithPersistentProperty(PersistentProperty property) { + if (PersistentPropertyType.forPersistentProperty(property) == FILE) { + result.add(property); + } + } + }); + return result; + } + + private List findLinkableAssociations(PersistentEntity persistentEntity) { + final List result = newArrayList(); + persistentEntity.doWithAssociations(new SimpleAssociationHandler() { + @Override + public void doWithAssociation(Association> association) { + if (associations.isLinkableAssociation(association.getInverse())) { + result.add(association); + } + } + }); + return result; + } + + private FilePropertyValue filePropertyValue(PersistentProperty persistentProperty, Object value) { + try { + if (!fileResourceStorage.fileExists(value, persistentProperty)) { + return new FilePropertyValue(false); + } + return new FilePropertyValue(entityLinks.linkForFilePropertyLink(value, persistentProperty)); + } catch (Exception e) { + return null; + } + } } \ No newline at end of file diff --git a/lightadmin-core/src/main/java/org/lightadmin/core/web/support/DynamicRepositoryEntityLinks.java b/lightadmin-core/src/main/java/org/lightadmin/core/web/support/DynamicRepositoryEntityLinks.java index 86dc9565..fa856bfd 100644 --- a/lightadmin-core/src/main/java/org/lightadmin/core/web/support/DynamicRepositoryEntityLinks.java +++ b/lightadmin-core/src/main/java/org/lightadmin/core/web/support/DynamicRepositoryEntityLinks.java @@ -1,98 +1,92 @@ -/* - * Copyright 2012-2014 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.lightadmin.core.web.support; - -import org.springframework.data.mapping.PersistentEntity; -import org.springframework.data.mapping.PersistentProperty; -import org.springframework.data.util.DirectFieldAccessFallbackBeanWrapper; -import org.springframework.hateoas.EntityLinks; -import org.springframework.hateoas.Identifiable; -import org.springframework.hateoas.Link; -import org.springframework.hateoas.LinkBuilder; - -import java.io.Serializable; - -/** - * TODO: Document me! - * - * @author Maxim Kharchenko (kharchenko.max@gmail.com) - */ -public class DynamicRepositoryEntityLinks implements EntityLinks { - - private EntityLinks delegate; - - private DynamicRepositoryEntityLinks(EntityLinks delegate) { - this.delegate = delegate; - } - - public static DynamicRepositoryEntityLinks wrap(EntityLinks delegate) { - return new DynamicRepositoryEntityLinks(delegate); - } - - public Link linkForFilePropertyLink(Object instance, PersistentProperty persistentProperty) { - PersistentEntity persistentEntity = persistentProperty.getOwner(); - Serializable id = idValue(instance, persistentEntity); - - return delegate.linkForSingleResource(persistentEntity.getType(), id).slash(persistentProperty.getName()).slash("file").withSelfRel(); - } - - @Override - public boolean supports(Class delimiter) { - return delegate.supports(delimiter); - } - - @Override - public LinkBuilder linkFor(Class type) { - return delegate.linkFor(type); - } - - @Override - public LinkBuilder linkFor(Class type, Object... parameters) { - return delegate.linkFor(type, parameters); - } - - @Override - public Link linkToCollectionResource(Class type) { - return delegate.linkToCollectionResource(type); - } - - @Override - public Link linkToSingleResource(Class type, Object id) { - if (id == null) { - return linkFor(type).slash("new").withSelfRel(); - } - return delegate.linkToSingleResource(type, id); - } - - @Override - public Link linkToSingleResource(Identifiable entity) { - return delegate.linkToSingleResource(entity); - } - - @Override - public LinkBuilder linkForSingleResource(Class type, Object id) { - return delegate.linkForSingleResource(type, id); - } - - @Override - public LinkBuilder linkForSingleResource(Identifiable entity) { - return delegate.linkForSingleResource(entity); - } - - private Serializable idValue(Object instance, PersistentEntity persistentEntity) { - return (Serializable) new DirectFieldAccessFallbackBeanWrapper(instance).getPropertyValue(persistentEntity.getIdProperty().getName()); - } +/* + * Copyright 2012-2014 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.lightadmin.core.web.support; + +import org.springframework.data.mapping.PersistentEntity; +import org.springframework.data.mapping.PersistentProperty; +import org.springframework.data.repository.support.Repositories; +import org.springframework.data.rest.core.config.RepositoryRestConfiguration; +import org.springframework.data.rest.core.mapping.ResourceMappings; +import org.springframework.data.rest.webmvc.spi.BackendIdConverter; +import org.springframework.data.rest.webmvc.support.PagingAndSortingTemplateVariables; +import org.springframework.data.rest.webmvc.support.RepositoryEntityLinks; +import org.springframework.data.util.DirectFieldAccessFallbackBeanWrapper; +import org.springframework.hateoas.EntityLinks; +import org.springframework.hateoas.Link; +import org.springframework.plugin.core.PluginRegistry; + +import java.io.Serializable; + +import static org.springframework.beans.PropertyAccessorFactory.forDirectFieldAccess; + +/** + * {@link RepositoryEntityLinks} for LightAdmin that allows creation + * of links for entities that are new (having no ID) and also adds + * support for creating links for File Properties. + * + * @author Maxim Kharchenko (kharchenko.max@gmail.com) + * @author Gazi Rahman + */ +public class DynamicRepositoryEntityLinks extends RepositoryEntityLinks implements EntityLinks { + + + public DynamicRepositoryEntityLinks(RepositoryEntityLinks delegate) { + super(repositories(delegate), mappings(delegate), config(delegate), templateVariables(delegate), idConverters(delegate)); + } + + public Link linkForFilePropertyLink(Object instance, + @SuppressWarnings("rawtypes") PersistentProperty persistentProperty) { + @SuppressWarnings("rawtypes") + PersistentEntity persistentEntity = persistentProperty.getOwner(); + Serializable id = idValue(instance, persistentEntity); + + return super.linkForSingleResource(persistentEntity.getType(), id).slash(persistentProperty.getName()).slash("file").withSelfRel(); + } + + @Override + public Link linkToSingleResource(Class type, Object id) { + if (id == null) { + return linkFor(type).slash("new").withSelfRel(); + } + return super.linkToSingleResource(type, id); + } + + private Serializable idValue(Object instance, + @SuppressWarnings("rawtypes") PersistentEntity persistentEntity) { + return (Serializable) new DirectFieldAccessFallbackBeanWrapper(instance).getPropertyValue(persistentEntity.getIdProperty().getName()); + } + + private static Repositories repositories(RepositoryEntityLinks delegate) { + return (Repositories) forDirectFieldAccess(delegate).getPropertyValue("repositories"); + } + + @SuppressWarnings("unchecked") + private static PluginRegistry> idConverters(RepositoryEntityLinks delegate) { + return (PluginRegistry>) forDirectFieldAccess(delegate).getPropertyValue("idConverters"); + } + + private static PagingAndSortingTemplateVariables templateVariables(RepositoryEntityLinks delegate) { + return (PagingAndSortingTemplateVariables) forDirectFieldAccess(delegate).getPropertyValue("templateVariables"); + } + + private static RepositoryRestConfiguration config(RepositoryEntityLinks delegate) { + return (RepositoryRestConfiguration) forDirectFieldAccess(delegate).getPropertyValue("config"); + } + + private static ResourceMappings mappings(RepositoryEntityLinks delegate) { + return (ResourceMappings) forDirectFieldAccess(delegate).getPropertyValue("mappings"); + } } \ No newline at end of file diff --git a/lightadmin-core/src/main/java/org/lightadmin/core/web/support/LightAdminLinkCollector.java b/lightadmin-core/src/main/java/org/lightadmin/core/web/support/LightAdminLinkCollector.java new file mode 100644 index 00000000..cfcdc593 --- /dev/null +++ b/lightadmin-core/src/main/java/org/lightadmin/core/web/support/LightAdminLinkCollector.java @@ -0,0 +1,47 @@ +/** + * + */ +package org.lightadmin.core.web.support; + +import java.util.List; + +import org.springframework.data.mapping.context.PersistentEntities; +import org.springframework.data.rest.core.support.SelfLinkProvider; +import org.springframework.data.rest.webmvc.mapping.Associations; +import org.springframework.data.rest.webmvc.mapping.LinkCollector; +import org.springframework.hateoas.Link; +import org.springframework.hateoas.Links; +import org.springframework.util.Assert; + +/** + * Overriding default {@link LinkCollector} so that correct + * Persistent Entity (not the {@link PersistentEntityWrapper} is + * used to generate the links. + * + * @author Gazi Rahman + * + */ +public class LightAdminLinkCollector extends org.springframework.data.rest.webmvc.mapping.LinkCollector { + + /** + * @param entities + * @param linkProvider + * @param associationLinks + */ + public LightAdminLinkCollector(PersistentEntities entities, SelfLinkProvider linkProvider, Associations associationLinks) { + super(entities, linkProvider, associationLinks); + } + + @Override + public Links getLinksFor(Object object, List existingLinks) { + + Assert.notNull(object, "Object must not be null!"); + + if (object instanceof PersistentEntityWrapper) { + object = ((PersistentEntityWrapper) object).getPersistentEntity(); + } + + return super.getLinksFor(object, existingLinks); + } + +} diff --git a/lightadmin-core/src/main/java/org/lightadmin/core/web/support/PersistentEntityWrapper.java b/lightadmin-core/src/main/java/org/lightadmin/core/web/support/PersistentEntityWrapper.java new file mode 100644 index 00000000..276f176e --- /dev/null +++ b/lightadmin-core/src/main/java/org/lightadmin/core/web/support/PersistentEntityWrapper.java @@ -0,0 +1,88 @@ +/** + * + */ +package org.lightadmin.core.web.support; + +import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_EMPTY; +import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; +import static com.google.common.collect.Maps.newHashMap; + +import java.util.Map; + +import org.lightadmin.core.config.domain.unit.DomainConfigurationUnitType; +import org.springframework.hateoas.Link; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonProperty; + +/** + * Wraps all the Persistent Entities. + *

+ * This class is moved out of {@link DynamicPersistentEntityResourceProcessor} + * so that it can be used in other classes as well, like the {@link LightAdminLinkCollector}. + * + * @author Gazi Rahman + * + */ + +public class PersistentEntityWrapper { + private String stringRepresentation; + private boolean managedDomainType; + private String primaryKey; + private Link domainLink; + private Object persistentEntity; + private Map> dynamicProperties; + + private PersistentEntityWrapper(Object persistentEntity, Map> dynamicProperties, String stringRepresentation, Link domainLink, boolean managedDomainType, String primaryKey) { + this.stringRepresentation = stringRepresentation; + this.domainLink = domainLink; + this.managedDomainType = managedDomainType; + this.persistentEntity = persistentEntity; + this.dynamicProperties = dynamicProperties; + this.primaryKey = primaryKey; + } + + public static PersistentEntityWrapper associatedPersistentEntity(String stringRepresentation, boolean managedDomainType, String primaryKey, Object primaryKeyValue, Link domainLink) { + Map persistentEntity = newHashMap(); + persistentEntity.put(primaryKey, primaryKeyValue); + + return new PersistentEntityWrapper(persistentEntity, null, stringRepresentation, domainLink, managedDomainType, primaryKey); + } + + public static PersistentEntityWrapper persistentEntity(Object instance, Map> dynamicProperties, String stringRepresentation, Link domainLink, boolean managedDomainType, String primaryKey) { + return new PersistentEntityWrapper(instance, dynamicProperties, stringRepresentation, domainLink, managedDomainType, primaryKey); + } + + @JsonProperty("string_representation") + public String getStringRepresentation() { + return stringRepresentation; + } + + @JsonProperty("primary_key") + public String getPrimaryKey() { + return primaryKey; + } + + @JsonProperty("managed_type") + public boolean isManagedDomainType() { + return managedDomainType; + } + + @JsonProperty("domain_link") + @JsonInclude(NON_NULL) + public Link getDomainLink() { + return domainLink; + } + + @JsonProperty("original_properties") + @JsonInclude(NON_NULL) + public Object getPersistentEntity() { + return persistentEntity; + } + + @JsonProperty("dynamic_properties") + @JsonInclude(NON_EMPTY) + public Map> getDynamicProperties() { + return dynamicProperties; + } +} diff --git a/lightadmin-core/src/main/resources/META-INF/resources/views/sections/top-navigation-section.jsp b/lightadmin-core/src/main/resources/META-INF/resources/views/sections/top-navigation-section.jsp index adbdd219..bb1f04e1 100644 --- a/lightadmin-core/src/main/resources/META-INF/resources/views/sections/top-navigation-section.jsp +++ b/lightadmin-core/src/main/resources/META-INF/resources/views/sections/top-navigation-section.jsp @@ -1,69 +1,70 @@ -<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %> - -<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> -<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> -<%@ taglib prefix="light" uri="http://www.lightadmin.org/tags" %> -<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %> -<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles" %> - - - - - -

-
-
- - - -
- - - Hello, - - - - - - - ! -
-
- -
-
- -
- -
- - -
- -
- - Fork me on GitHub -
- -
-
-
+<%@ page contentType="text/html;charset=UTF-8" language="java" pageEncoding="UTF-8" %> + +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> +<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %> +<%@ taglib prefix="light" uri="http://www.lightadmin.org/tags" %> +<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %> +<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles" %> + + + + + +
+
+
+ + + + +
+ + + Hello, + + + + + + + ! +
+
+ +
+
+ +
+ +
+ + +
+ +
+ + Fork me on GitHub +
+ +
+
+
\ No newline at end of file diff --git a/lightadmin-sandbox/pom.xml b/lightadmin-sandbox/pom.xml index 02d28756..b9fda459 100644 --- a/lightadmin-sandbox/pom.xml +++ b/lightadmin-sandbox/pom.xml @@ -7,11 +7,11 @@ lightadmin-parent org.lightadmin - 1.2.0.BUILD-SNAPSHOT + 1.3.1.BUILD-SNAPSHOT lightadmin-sandbox - 1.2.0.BUILD-SNAPSHOT + 1.3.1.BUILD-SNAPSHOT war LightAdmin SandBox diff --git a/lightadmin-tests/pom.xml b/lightadmin-tests/pom.xml index 79c30063..2ace6e5e 100644 --- a/lightadmin-tests/pom.xml +++ b/lightadmin-tests/pom.xml @@ -1,235 +1,235 @@ - - - - 4.0.0 - - - org.lightadmin - lightadmin-parent - 1.2.0.BUILD-SNAPSHOT - - - lightadmin-tests - 1.2.0.BUILD-SNAPSHOT - - LightAdmin Selenium - - - 8080 - - 2.45.0 - 1.4.01 - - - - - org.lightadmin - lightadmin-sandbox - ${project.version} - war - - - org.lightadmin - lightadmin-sandbox - ${project.version} - classes - - - - org.seleniumhq.selenium - selenium-java - ${selenium-java.version} - - - - xml-apis - xml-apis - ${xml-apis.version} - - - - com.google.guava - guava - - - - org.slf4j - slf4j-api - - - ch.qos.logback - logback-classic - runtime - - - - org.springframework - spring-core - - - commons-logging - commons-logging - - - - - org.springframework - spring-context - - - - javax.servlet.jsp - javax.servlet.jsp-api - - - - org.springframework - spring-test - - - junit - junit - - - - - - - - org.apache.maven.plugins - maven-failsafe-plugin - 2.12 - - - integration-test - integration-test - - integration-test - - - - **/*.class - - true - - - - verify - verify - - verify - - - - - - org.apache.maven.plugins - maven-surefire-plugin - 2.12 - - true - - - - - - - - - test-mode - - - mode - test - - - - - - org.apache.maven.plugins - maven-failsafe-plugin - - - org.apache.maven.plugins - maven-surefire-plugin - - - - - - dev-mode - - - mode - dev - - - - - - org.codehaus.cargo - cargo-maven2-plugin - 1.2.4 - - - start-cargo - pre-integration-test - - start - - - - stop-cargo - post-integration-test - - stop - - - - - - jetty8x - - org.eclipse.jetty - jetty-distribution - 8.1.8.v20121106 - - - - - ${project.groupId} - lightadmin-sandbox - war - - lightadmin-sandbox - - - - - - ${container.port} - - - - ${basedir}/src/test/jetty8x/jetty-logging.xml - etc - - - - - - - org.apache.maven.plugins - maven-failsafe-plugin - - - org.apache.maven.plugins - maven-surefire-plugin - - - - - - - + + + + 4.0.0 + + + org.lightadmin + lightadmin-parent + 1.3.1.BUILD-SNAPSHOT + + + lightadmin-tests + 1.3.1.BUILD-SNAPSHOT + + LightAdmin Selenium + + + 8080 + + 2.45.0 + 1.4.01 + + + + + org.lightadmin + lightadmin-sandbox + ${project.version} + war + + + org.lightadmin + lightadmin-sandbox + ${project.version} + classes + + + + org.seleniumhq.selenium + selenium-java + ${selenium-java.version} + + + + xml-apis + xml-apis + ${xml-apis.version} + + + + com.google.guava + guava + + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + runtime + + + + org.springframework + spring-core + + + commons-logging + commons-logging + + + + + org.springframework + spring-context + + + + javax.servlet.jsp + javax.servlet.jsp-api + + + + org.springframework + spring-test + + + junit + junit + + + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + 2.12 + + + integration-test + integration-test + + integration-test + + + + **/*.class + + true + + + + verify + verify + + verify + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 2.12 + + true + + + + + + + + + test-mode + + + mode + test + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + org.apache.maven.plugins + maven-surefire-plugin + + + + + + dev-mode + + + mode + dev + + + + + + org.codehaus.cargo + cargo-maven2-plugin + 1.2.4 + + + start-cargo + pre-integration-test + + start + + + + stop-cargo + post-integration-test + + stop + + + + + + jetty8x + + org.eclipse.jetty + jetty-distribution + 8.1.8.v20121106 + + + + + ${project.groupId} + lightadmin-sandbox + war + + lightadmin-sandbox + + + + + + ${container.port} + + + + ${basedir}/src/test/jetty8x/jetty-logging.xml + etc + + + + + + + org.apache.maven.plugins + maven-failsafe-plugin + + + org.apache.maven.plugins + maven-surefire-plugin + + + + + + + diff --git a/pom.xml b/pom.xml index 0f43fefa..c30c0353 100644 --- a/pom.xml +++ b/pom.xml @@ -1,70 +1,70 @@ - - - 4.0.0 - org.lightadmin - lightadmin-parent - 1.2.0.BUILD-SNAPSHOT - pom - - LightAdmin Dev Kit - - - UTF-8 - UTF-8 - - 1.7 - 1.7 - - 1.1.2.RELEASE - 1.2 - - 1.0.0.BUILD-SNAPSHOT - - - - - - io.spring.platform - platform-bom - ${spring.platform.version} - pom - import - - - - org.lightadmin - lightadmin - ${project.version} - - - org.lightadmin - light-logging-configurer - ${light-logging-configurer.version} - - - - org.glassfish.web - jstl-impl - ${jstl.version} - - - javax.servlet - servlet-api - - - javax.servlet.jsp - jsp-api - - - - - - - - lightadmin-core - lightadmin-sandbox - lightadmin-tests - - + + + 4.0.0 + org.lightadmin + lightadmin-parent + 1.3.1.BUILD-SNAPSHOT + pom + + LightAdmin Dev Kit + + + UTF-8 + UTF-8 + + 1.7 + 1.7 + + Brussels-SR6 + 1.2 + + 1.0.0.BUILD-SNAPSHOT + + + + + + io.spring.platform + platform-bom + ${spring.platform.version} + pom + import + + + + org.lightadmin + lightadmin + ${project.version} + + + org.lightadmin + light-logging-configurer + ${light-logging-configurer.version} + + + + org.glassfish.web + jstl-impl + ${jstl.version} + + + javax.servlet + servlet-api + + + javax.servlet.jsp + jsp-api + + + + + + + + lightadmin-core + lightadmin-sandbox + lightadmin-tests + + \ No newline at end of file