/*
* 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.beans.security.LoginLocal;
import framework.beans.security.SecurityInterface;
import framework.beans.security.SessionSecurityDetails;
import framework.generic.ClipsServerException;
import framework.generic.ESecurity;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.LinkedList;
import java.util.List;
import javax.ejb.EJB;
import javax.ejb.EJBException;
import framework.security.RightChecker;
import framework.security.SecurityChecker;
import framework.security.UserRight;
import framework.security.UserRightsSetAbstract;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import javax.persistence.Query;
/**
*
* @author axe
*/
public abstract class SecuredBean extends FindEntity
implements SecurityInterface, RightChecker /*, TransactionalBean*/ {
@EJB
LoginLocal loginBean;
protected BeanRights rights; // обязательно устанавливать в подклассах
private SessionSecurityDetails sessionData;
/** Инициализация прав бина на выполнение комманд. Этот метод следует обязательно
* переопределять во всех подклассах FacadeBean. Права бина будут оставлены у бина и
* будут переданны клиенту.
*/
protected void initBeanRights() throws ClipsServerException {
rights = new BeanRights(null);
}
/**
* Определить, в рамках какой сессии создан бин. Если этот метод не вызвать перед
* началом работы с бином, бин не получит прав пользователя и большинство методов будут
* возвращать ошибку системы безопастности.
* @param aSessionId
* @return
* @throws generic.ClipsServerException
*/
@Override
public BeanRights setSession(int aSessionId) throws ClipsServerException {
try {
sessionData = loginBean.getSession(aSessionId);
} catch (Exception ex) {
// указана не верная сессия клиента. Нас атакуют! Или баг в программе :)
// ждём 3 секунды.
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// DO NOTHING
}
// Испускаем потомка RuntimeExeption, дабы убить бин и сделать жизнь взломщика ещё сложнее.
throw new EJBException("Внутренняя ошибка: Бин не может получить информацию о правах", ex);
}
try {
initBeanRights();
} catch (Exception ex) {
if (ex instanceof ClipsServerException) {
throw (ClipsServerException) ex;
} else {
throw new ClipsServerException("Не могу инициализировать права на команды бина", ex);
}
}
return rights;
}
@Override
public int getSessionId() {
return sessionData.sessionId;
}
public int getCollaboratorId() {
return sessionData.collaboratorId;
}
protected final boolean isCommandAccessible(int aCommandId) throws ESecurity {
return rights.isCommandAccessible(aCommandId);
}
protected final void checkAuthentic() throws ESecurity {
if (!isAuthentic()) {
throw new ESecurity(SecurityChecker.msgClientIsNotAuthentic);
}
}
protected final void checkCommandAccessibility(int aCommandId) throws ESecurity {
checkAuthentic();
int r = rights.getCommandAccessReason(aCommandId);
if (UserRightsSetAbstract.SecurityOn && r < 0) {
throw new ESecurity(SecurityChecker.getClientHasNoRightMsg(r));
}
}
@Override
final public boolean hasRight(UserRight aRight) {
return SecurityChecker.hasRight(sessionData.currentUserRights, aRight);
}
protected final boolean isAuthentic() {
return sessionData != null && getSessionId() != 0 && loginBean.hasSession(getSessionId());
}
protected final boolean isSuperUser() {
return sessionData.isSuperUser;
}
protected final int RightPresence(int aRightId) {
return SecurityChecker.RightPresence(sessionData.currentUserRights, aRightId);
}
protected void checkCurrentCollaborator(int id)
throws ClipsServerException {
if(id != getCollaboratorId()) {
throwNeedAdminSecurityException("Попытка подмены текущего сотрудника");
}
}
/**
* если админ (суперправо), то не выкидывать исключение
* @param str
* @throws ESecurity
*/
protected void throwNeedAdminSecurityException(String str) throws ESecurity {
if (sessionData.isSuperUser) {
return;
}
throw new ESecurity(str);
}
/**
* Проверяет, в будущем ли указанный день. Если день уже прошел,
* выкидывает исключение
* @param cal дата
* @throws ClipsServerException
*/
protected void checkIsNotInThePast(Calendar cal) throws ClipsServerException {
if (sessionData.isSuperUser) {
return;
}
Calendar zero = GregorianCalendar.getInstance();
zero.set(Calendar.HOUR_OF_DAY, 0);
zero.set(Calendar.MINUTE, 0);
zero.set(Calendar.SECOND, 0);
zero.set(Calendar.MILLISECOND, 0);
if(zero.after(cal)) {
throw new ClipsServerException("Попытка изменения данных за уже прошедшие дни: сегодня "
+ zero.getTime() + ", изменяемая дата " + cal.getTime());
}
}
/**
* Проверяет, в будущем ли указанный день. Если день уже прошел,
* выкидывает исключение
* @param date дата
* @throws ClipsServerException
*/
protected void checkIsNotInThePast(Date date)
throws ClipsServerException {
Calendar cal = GregorianCalendar.getInstance();
cal.setTime(date);
checkIsNotInThePast(cal);
}
/**
* Проверяет, в будущем ли указанный день. Если день уже прошел,
* выкидывает исключение
* @param day день (1-31)
* @param month месяц (1-12)
* @param year год (1900-2100)
* @throws ClipsServerException
*/
protected void checkIsNotInThePast(int day, int month, int year)
throws ClipsServerException {
Calendar cal = GregorianCalendar.getInstance();
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, month - 1);
cal.set(Calendar.DAY_OF_MONTH, day);
cal.set(Calendar.HOUR_OF_DAY, 0);
cal.set(Calendar.MINUTE, 0);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
checkIsNotInThePast(cal);
}
/**
* Ищет и возвращяет список деталей сущностей ссылающихся на
* сущность entity полем member.
* тоесть если передать в каществе entity - EMC пациента,
* в качестве childClass - Disease.class, a качестве member "emc"
* то будут возвращены все заболевания (Disease) привязанные к EMC пациента
* @param <K>
* @param <T>
* @param entity - сущьность на которую должен ссылатся member дочерней сущности childClass
* @param childClass - класс дочерней сущности например Prescription.class
* @param member - член класса который ссылается на сущность бина
* например "serviceRender" для Prescription.class и ServiceRenderBean
* @return
* @throws ClipsServerException
*/
protected <K extends EntityDetails, T extends GenericEntity<K>> ArrayList<K>
loadChildDetailsList(GenericEntity entity, Class <T> childClass, String member)
throws ClipsServerException {
Collection<T> entitys = findEntityList(childClass, member, entity);
return getEntytyDetailsList(entitys);
}
/**
* создает по списку сущностей, список деталей используя функцию getDetails
* и используя this в качестве RightChecker-а this
* @param <K>
* @param <T>
* @param entitys - коллекция дочерних сущьностей
* @return
*/
public <K extends EntityDetails, T extends GenericEntity<K>>
ArrayList<K> getEntytyDetailsList(Collection<T> entitys){
ArrayList<K> list = new ArrayList<K>(entitys.size());
for (T entity : entitys) {
list.add(entity.getDetails(this));
}
return list;
}
/**
*
* @param <T>
* @param clazz
* @param sessionID
* @return
* @throws ClipsServerException
* @deprecated Юзайте getBean(Class<T> clazz)
*/
@Deprecated
@Override
protected <T extends SecurityInterface> T getBean(Class<T> clazz, int sessionID) throws ClipsServerException {
return super.getBean(clazz, sessionID);
}
protected <T extends SecurityInterface> T getBean(Class<? extends T> clazz) throws ClipsServerException {
return super.getBean(clazz, getSessionId());
}
protected final CollaboratorAbstract getCollaborator() throws ClipsServerException {
return findEntity(CollaboratorAbstract.class, getCollaboratorId());
}
/**
* Записывает в базу список документов аудита и возвращает детали.
* Перед вызовом нуобходимо обязательно произвести проверку изменений методом
* AuditDoc.check();
* @param list
* @return
* @throws ESecurity
*/
protected List<AuditDetails> persistAudit(List<AuditDoc> list) throws ESecurity {
List<AuditDetails> details = new LinkedList<AuditDetails>();
for (AuditDoc doc : list) {
AuditDetails auditDetails = persistAudit(doc);
if (auditDetails != null) {
details.add(auditDetails);
}
}
return details;
}
/**
* Записывает документ аудита в базу, если изменений не было возвращент null
* @param auditDoc
*/
protected AuditDetails persistAudit(AuditDoc auditDoc) throws ESecurity {
if (!auditDoc.isChecked()) {
throw new ESecurity("В документе аудита не была произведена проверка изменений");
}
if (auditDoc.getResult() == null) {
return null;
}
Audit audit = new Audit();
audit.setDate(auditDoc.getDate());
audit.setValue(auditDoc.getResult());
audit.setCollaborator(auditDoc.collab);
audit.setEntityClass(auditDoc.getClassName());
audit.setEntityId(auditDoc.getId() == null ? 0 : auditDoc.getId());
// String dsa = "";
// for(int i=0; i<256; i++) {
// byte b = (byte)Math.floor(Math.random()*256);
// String tmp = Integer.toHexString(((int)b) & 0xFF).toUpperCase();
// dsa += tmp;
// }
// audit.setDsa(dsa);
manager.persist(audit);
manager.flush();
manager.refresh(audit);
return audit.getDetails(this);
}
/**
* Удаляет сущности используя аудит
* @param <T>
* @param entityClass
* @param fields
* @param auditDocList
* @throws ClipsServerException
*/
protected <T extends BaseEntity> void deleteEntityList2(Class<T> entityClass, Field[] fields, List<AuditDoc> auditDocList) throws ClipsServerException {
try {
List<Field> list = (null == fields? new ArrayList<Field>(0): Arrays.asList(fields));
String sql = makeFeldSelect(SelectType.select, null, entityClass, null, null, list, null);
// System.out.println("sql debug " + sql);
Query query = manager.createQuery(sql);
setFieldsParamiters(query, list);
@SuppressWarnings("unchecked")
List<T> toDeleteList = query.getResultList();
for (T entity : toDeleteList) {
AuditDoc<T> auditDoc = new AuditDoc<T>(entity, getCollaborator());
removeEntity(entity);
auditDoc.check(null);
auditDocList.add(auditDoc);
}
}
catch (Exception ex) {
throw new ClipsServerException("Попытка удаления не удалась: ", ex);
}
}
}