/**
* Licensed to Apereo under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright ownership. Apereo
* licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of the License at the
* following location:
*
* <p>http://www.apache.org/licenses/LICENSE-2.0
*
* <p>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.apereo.portal;
import com.googlecode.ehcache.annotations.Cacheable;
import com.googlecode.ehcache.annotations.TriggersRemove;
import com.googlecode.ehcache.annotations.key.ListCacheKeyGenerator;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.dao.support.DataAccessUtils;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
/**
* This class provides access to the entity types used by <code>IBasicEntities</code> and the
* classes in <code>org.apereo.portal.groups</code> and <code>org.apereo.portal.concurrency</code>.
*
* <p>Each type is associated with an <code>Integer</code> used to represent the type in the portal
* data store. This class translates between the <code>Integer</code> and <code>Class</code> values.
*
* @see org.apereo.portal.IBasicEntity
*/
@Repository("entityTypes")
public class EntityTypes {
private static final RowMapper<Class<?>> CLASS_ROW_MAPPER =
new RowMapper<Class<?>>() {
private final Logger logger = LoggerFactory.getLogger(getClass());
@Override
public Class<?> mapRow(ResultSet rs, int rowNum) throws SQLException {
final String className = rs.getString("ENTITY_TYPE_NAME");
try {
return Class.forName(className);
} catch (ClassNotFoundException e) {
logger.error(
"Failed to find the specified EntityType class '{}'; "
+ "this is either a catastrophic problem (is the portal working "
+ "at all?) or an artifact of orphaned data.",
className);
// These will be removed from the allEntityTypes collection
return null;
}
}
};
private JdbcOperations jdbcOperations;
private ICounterStore counterStore;
@Autowired
public void setJdbcOperations(@Qualifier("PortalDb") JdbcOperations jdbcOperations) {
this.jdbcOperations = jdbcOperations;
}
@Autowired
public void setCounterStore(ICounterStore counterStore) {
this.counterStore = counterStore;
}
@Cacheable(
cacheName = "org.apereo.portal.EntityTypes.CLASS_BY_ID",
keyGeneratorName = ListCacheKeyGenerator.DEFAULT_BEAN_NAME
)
public Class<? extends IBasicEntity> getEntityTypeFromID(Integer id) {
final List<Class<?>> result =
this.jdbcOperations.query(
"SELECT ENTITY_TYPE_NAME FROM UP_ENTITY_TYPE WHERE ENTITY_TYPE_ID = ?",
CLASS_ROW_MAPPER,
id);
@SuppressWarnings(
"unchecked") // There is an unused(?) row for java.lang.Object that looks as though it will fail here
Class<? extends IBasicEntity> rslt =
(Class<? extends IBasicEntity>) DataAccessUtils.singleResult(result);
return rslt;
}
@Cacheable(
cacheName = "org.apereo.portal.EntityTypes.ID_BY_CLASS",
keyGeneratorName = ListCacheKeyGenerator.DEFAULT_BEAN_NAME
)
public Integer getEntityIDFromType(Class<? extends IBasicEntity> type) {
return DataAccessUtils.singleResult(
this.jdbcOperations.queryForList(
"SELECT ENTITY_TYPE_ID FROM UP_ENTITY_TYPE WHERE ENTITY_TYPE_NAME = ?",
Integer.class,
type.getName()));
}
@Cacheable(
cacheName = "org.apereo.portal.EntityTypes.ALL",
keyGeneratorName = ListCacheKeyGenerator.DEFAULT_BEAN_NAME
)
public Iterator<Class<?>> getAllEntityTypes() {
final List<Class<?>> entityTypes =
this.jdbcOperations.query(
"SELECT ENTITY_TYPE_NAME FROM UP_ENTITY_TYPE", CLASS_ROW_MAPPER);
// Filter null values
final Set<Class<?>> rslt = new HashSet<>();
for (Class<?> clazz : entityTypes) {
if (clazz != null) {
rslt.add(clazz);
}
}
return rslt.iterator();
}
@TriggersRemove(
cacheName = {"org.apereo.portal.EntityTypes.ALL"},
removeAll = true
)
@Transactional
public void addEntityTypeIfNecessary(Class<? extends IBasicEntity> newType, String description)
throws java.lang.Exception {
final Integer existingId = this.getEntityIDFromType(newType);
if (existingId != null) {
//Entity type already exists, ignore call
return;
}
final int nextId = counterStore.getNextId("UP_ENTITY_TYPE");
this.jdbcOperations.update(
"INSERT INTO UP_ENTITY_TYPE (ENTITY_TYPE_ID, ENTITY_TYPE_NAME, DESCRIPTIVE_NAME) VALUES (?, ?, ?)",
nextId,
newType.getName(),
description);
}
@TriggersRemove(
cacheName = {
"org.apereo.portal.EntityTypes.CLASS_BY_ID",
"org.apereo.portal.EntityTypes.ID_BY_CLASS",
"org.apereo.portal.EntityTypes.ALL"
},
removeAll = true
)
@Transactional
public void deleteEntityType(Class<?> type) throws SQLException {
this.jdbcOperations.update(
"DELETE FROM UP_ENTITY_TYPE WHERE ENTITY_TYPE_NAME = ?", type.getName());
}
}