/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package framework.beans;
import framework.audit.Audit;
import framework.audit.AuditDetails;
import framework.audit.AuditDoc;
import framework.beans.collaborator.CollaboratorAbstract;
import framework.beans.security.BeanRights;
import framework.generic.ClipsServerException;
import framework.generic.EDataIntegrity;
import framework.generic.ESecurity;
import framework.generic.HasEntityInfo;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import framework.security.RightChecker;
import framework.utils.DateTimeUtils;
import java.util.LinkedList;
/**
*
* @param <GEN>
* @author axe
*/
abstract public class FacadeBean<GEN extends GenericEntity> extends SecuredBean
implements EntityFacade {
public static int COMMAND_READ = 0;
public static int COMMAND_CREATE = 1;
public static int COMMAND_MODIFY = 2;
public static int COMMAND_REMOVE = 3;
private boolean justCreated;
private int entityID;
private Class<GEN> cls;
public FacadeBean(Class<GEN> cls) {
this.cls = cls;
}
protected int getId() {
return entityID;
}
public Class<GEN> getEntityClass() {
return cls;
}
private GEN getEntity() throws ClipsServerException {
if(entityID == 0) {
try {
return cls.newInstance();
} catch (Exception ex) {
throw new ClipsServerException("Неожиданная ошибка при создании новых данных на сервере", ex);
}
}
else {
//entity = (GEN) findEntity(cls, anId);
return findEntity(cls, entityID);
}
}
protected GEN getExistentEntity() throws ClipsServerException {
checkEntityExist();
return getEntity();
}
@Override
public String getEntityName() {
return getEntityHumanName(cls);
}
/**
* Этот метод следует обязательно вызывать перед работой с бином.
* @param anId - идентификатор сущности, с которой будет работать бин. 0 - если создаётся новая
* сущность.
* @param aSessionId - идентификатор сессии. Без него работу заблокирует система безопасности.
* @return
* @throws generic.ClipsServerException
*/
@Override
public BeanRights initByID(int anId, int aSessionId)
throws ClipsServerException {
entityID = anId;
if(anId == 0) {
/*try {
entity = cls.newInstance();
} catch (Exception ex) {
throw new ClipsServerException("Неожиданная ошибка при инициализации сервера", ex);
}*/
} else {
//entity = (GEN) findEntity(cls, anId);
findEntity(cls, anId);
}
justCreated = anId == 0;
setSession(aSessionId);
return rights;
}
public boolean isJustCreated() {
return justCreated;
}
/**
* В системе безопасности это комманда COMMAND_READ. В этом классе (FacadeBean) этот
* метод - только начало для метода getDetails всех подклассов. Ни чего не возвращает, а
* только проверяет наличие прав на эту комманду.
* @return
* @throws generic.ClipsServerException
*/
@Override
public EntityDetails getDetails() throws ClipsServerException {
checkEntityExist();
checkCommandAccessibility(COMMAND_READ);
return getEntity().getDetails((RightChecker) this);
}
/**
* Этот метод позволяет создавать новую или редактировать уже существующую сущность.
* В системе безопасности это комманда COMMAND_CREATE или COMMAND_MODIFY.
* Здесь проверяется наличие прав на комманду, возможность выполнения (проверка целостности и
* корректности, переопределить в методе checkAccessibilityForUpdate), и вызывается
* updateUnconditional.
* @param details
* @return
* @throws generic.ClipsServerException
*/
@Override
public ModificationInfo update(EntityDetails details) throws ClipsServerException {
try {
List<AuditDoc> auditList = new LinkedList<AuditDoc>();
checkCommandAccessibility(isJustCreated() ? COMMAND_CREATE : COMMAND_MODIFY);
GEN entity = getEntity();
AuditDoc<GEN> auditDoc = new AuditDoc<GEN>(entity, getCollaborator());
onUpdate(entity, details, auditDoc, auditList);
boolean newEntity = (entityID == 0);
int id = saveEntity(entity);
checkAudit(auditList, auditDoc, entity);
details.setId(entityID);
afterUpdate(entity, newEntity, details, auditList);
entityID = id;
List<AuditDetails> auditInfo = persistAudit(auditList);
return new ModificationInfo(id, auditInfo);
} catch (ClipsServerException ex) {
throw ex;
} catch (Exception ex) {
throw new ClipsServerException("Не удалось сохранить: ", ex);
}
}
/**
* Проверяет возможность удаления сущности.
* В этот методе не следует добавлять проверку наличия прав, это сделанно за его пределами.
* @param entity
* @TODO Сейчас этот метод НЕ абстрактный, чтобы не пришлось исправлять всё сразу.
* В последствии для поиска случаев, когда этот метод не реализован, можно сделать его абстрактным.
* @throws ClipsServerException
*/
protected void onRemove(GEN entity, List<AuditDoc> auditDocList) throws ClipsServerException {
/* java.lang.reflect.Field fields[] = cls.getDeclaredFields();
for(int i=0; i<fields.length; i++) {
Class fc = fields[i].getDeclaringClass();
if(fc.isInstance(GenericEntity.class)) {
}
}*/
}
/**
* Проверяет возможность создания или изменения сущности учитывая принятые детали.
* В этот методе не следует добавлять проверку наличия прав, это сделанно за его пределами.
* В последствии для поиска случаев, когда этот метод не реализован, можно сделать его абстрактным.
* Внимание! В auditDocList добавлять ничего не надо, если изменяется только сущность,
* закрываемая бином. Если же изменяются сопутствующие сущности, то создается документ
* аудита, затем сопутствующие сущности изменяются, записываются в базу, рефрешаются для
* получения ID, документу аудита делается check, и добавляем его к auditDocList.
* @param entity
* @param details
* @param auditDoc передается для возможных извращений (к примеру CheckupBean)
* @param auditDocList передается для заталкивания документов аудита для
* сопутсвующих измененных сущностей
* @throws ClipsServerException
*/
abstract protected void onUpdate(GEN entity, EntityDetails details, AuditDoc auditDoc, List<AuditDoc> auditDocList) throws ClipsServerException;
/**
* Выполняет некоторые необходимые действия которые должны быть реализованы после создания
* или изменения сущности
* @param entity
* @param isNewEntity
* @param details
* @throws ClipsServerException
*/
protected void afterUpdate(GEN entity, boolean isNewEntity, EntityDetails details, List<AuditDoc> auditDocList) throws ClipsServerException {
};
/**
* Этот метод позволяет удаляет сущность.
* В системе безопасности это комманда COMMAND_REMOVE.
* Здесь проверяется наличие прав на комманду, возможность выполнения (проверка целостности и
* корректности, переопределить в методе checkAccessibilityForRemove), и вызывается
* removeUnconditional.
* @throws ClipsServerException
*/
@Override
public ModificationInfo remove() throws ClipsServerException {
try {
checkCommandAccessibility(COMMAND_REMOVE);
checkEntityExist();
GEN entity = getEntity();
List<AuditDoc> auditDocList = new LinkedList<AuditDoc>();
AuditDoc<GEN> auditDoc = new AuditDoc<GEN>(entity, getCollaborator());
auditDocList.add(auditDoc);
//Нельзя нарушать последовательность вызовов
onRemove(entity, auditDocList);
auditDoc.check(null);
removeEntity(entity);
List<AuditDetails> auditInfo = persistAudit(auditDocList);
return new ModificationInfo(entity.getId(), auditInfo);
} catch (ClipsServerException ex) {
throw ex;
} catch (Exception ex) {
throw new ClipsServerException("Ошибка удаления", ex);
}
}
/**
* Проверка, сохранена ли основная сущность бина
* @throws EDataIntegrity если не сохранена, выбрасывается исключение
*/
protected void checkEntityExist() throws EDataIntegrity {
if(entityID == 0) {
throw new EDataIntegrity("Сущность должна быть предварительно сохранена");
}
}
/**
* Проверка, соответсвтвует ли указанная сущность основной сущности бина
* @param gent
* @throws ClipsServerException если не соответствует, выбрасывается исключение
*/
protected void checkTheSame(GenericEntity gent) throws ClipsServerException {
if(gent.getId() != getEntity().getId()) {
throw new EDataIntegrity("Зафиксирована попытка переноса данных");
}
}
protected void checkDate(Date date) throws ClipsServerException {
if(!DateTimeUtils.belongsToCurrentDay(date)) {
throw new ESecurity("Срок редактирования вышел");
}
}
/**
* Ищет и возвращяет детали сущностей ссылающихся на сущьность текущего бина
* @param <K>
* @param <T>
* @param childClass - класс дочерней сущности например Prescription.class
* @param member - член класса который ссылается на сущность бина
* например "serviceRender" для Prescription.class и ServiceRenderBean
* @return
* @throws ClipsServerException
*/
protected <K extends EntityDetails, T extends GenericEntity<K>>
ArrayList<K> loadChildDetailsList(Class<T> childClass, String member)
throws ClipsServerException {
GEN entity = getExistentEntity();
return loadChildDetailsList(entity, childClass, member);
}
protected <T extends GenericEntity> void checkEntityNotRef(Class<T> clazz, String member) throws EDataIntegrity{
checkEntityNotRef(clazz, member, null);
}
protected void checkEntityNotRef(Class clazz, String member, String message) throws EDataIntegrity{
GEN entity = manager.find(cls, entityID);
checkEntityNotRef(entity, clazz, member, message);
}
/**
* проверка связана ли сущность с другими сущностями
* @param <T>
* @param entity
* @param clazz
* @param member
* @param message
* @throws framework.generic.EDataIntegrity
*/
protected <T extends GenericEntity> void checkEntityNotRef(GEN entity, Class<T> clazz, String member, String message) throws EDataIntegrity{
if(entityID == 0) {
return;
}
if (entity == null){
return;
}
// List entityList = findEntityList(clazz, new Field[]{new Field(member, entity)});
Field[] f = new Field[]{new Field(member, entity)};
int count = getEntityCount(clazz, f);// entityList.size();
if (count > 0){
List<T> list = findEntityListWithResCount(clazz, f, "", 1);
if (list.isEmpty()){
}else{
Object linked = list.get(0);
String linkInfo = "";
if (linked instanceof HasEntityInfo) {
linkInfo = "\n[" + ((HasEntityInfo) linked).getInfo() + "]";
}
if (message == null){
message = "Нельзя удалить объект \"%1$s\" так как на него ссылается \"%2$s\", перед удалением надо удалить или отредактировать \"%2$s\"";
}
throw new EDataIntegrity(String.format(message, getEntityHumanName(cls), getEntityHumanName(clazz), count) + linkInfo);
}
}
}
protected <T extends GenericEntity> void checkAudit(List<AuditDoc> list,
AuditDoc<T> auditDoc, T entity) throws ClipsServerException {
if(auditDoc.check(entity)) {
list.add(auditDoc);
}
}
}