/*
* Copyright 2009-2012 by KNURT Systeme (http://www.knurt.de)
*
* Licensed under the Creative Commons License Attribution-NonCommercial-ShareAlike 3.0 Unported;
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://creativecommons.org/licenses/by-nc-sa/3.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 de.knurt.fam.core.persistence.dao;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import org.springframework.dao.DataIntegrityViolationException;
import de.knurt.fam.core.aspects.logging.FamLog;
import de.knurt.fam.core.model.config.Facility;
import de.knurt.fam.core.model.persist.FacilityAvailability;
import de.knurt.fam.core.model.persist.User;
import de.knurt.fam.core.persistence.dao.config.FacilityConfigDao;
import de.knurt.fam.core.util.time.FacilityAvailabilityMerger;
import de.knurt.heinzelmann.util.time.SimpleTimeFrame;
import de.knurt.heinzelmann.util.time.TimeFrame;
/**
* dao for all time frames of facilities.
*
* @see FacilityAvailability
* @author Daniel Oltmanns
* @since 0.20090424
*/
public abstract class FacilityDao extends AbstractFamDao<FacilityAvailability> {
private Long idToSet = null;
/**
* return all {@link FacilityAvailability}s for the facility, that overlaps
* with the given {@link TimeFrame}. this includes all
* {@link FacilityAvailability} s, where the iteration is set and is
* overlapping with this iteration. this ignores all parent facilities'
* availabilities!
*
* @param fromTo
* timeframe to check
* @param facilityKey
* the key of the facilities, all saved time frames in databases
* are asked for.
* @return all {@link FacilityAvailability}s, that overlaps with the given
* time frame.
*/
public List<FacilityAvailability> getFacilityAvailabilitiesIgnoreParents(TimeFrame fromTo, String facilityKey) {
List<FacilityAvailability> results = new ArrayList<FacilityAvailability>();
List<FacilityAvailability> candidates = this.getFacilityAvailabilities(facilityKey);
for (FacilityAvailability candidate : candidates) {
if (candidate.overlaps(fromTo)) {
results.add(candidate);
}
}
return results;
}
/**
* return all {@link FacilityAvailability}s for the facility, that overlaps
* with the given {@link TimeFrame}. this includes all
* {@link FacilityAvailability} s, where the iteration is set and is
* overlapping with this iteration and {@link FacilityAvailability}s set for
* parents of given facilityKey.
*
* @param fromTo
* timeframe to check
* @param facility
* the facility, all saved time frames in databases are asked
* for.
* @return all {@link FacilityAvailability}s, that overlaps with the given
* time frame.
*/
public List<FacilityAvailability> getFacilityAvailabilitiesFollowingParents(TimeFrame fromTo, Facility facility) {
List<FacilityAvailability> result = this.getFacilityAvailabilitiesIgnoreParents(fromTo, facility.getKey());
if (facility.hasParent()) {
result.addAll(this.getFacilityAvailabilitiesFollowingParents(fromTo, facility.getParentFacility()));
}
return result;
}
/**
* return all facility availabilities set for the given facility. sortation:
* by the start of the base time frame.
*
* @param facilityKey
* key representing a facility.
* @return all facility availabilities set for the given facility.
*/
public abstract List<FacilityAvailability> getFacilityAvailabilities(String facilityKey);
/**
* return true, if {@link FacilityAvailability} cannot be saved. that's if:
* <ul>
* <li>facility key does not exist</li>
* <li>information about user set this is missed</li>
* <li>
* given {@link FacilityAvailability} is a {@link FacilityAvailability} and
* it is maybe available.</li>
* </ul>
*
* @param tf
* to check
* @return true, if {@link FacilityAvailability} cannot be saved.
*/
@Override
protected boolean isDataIntegrityViolation(FacilityAvailability tf, boolean onInsert) {
boolean result = !FacilityConfigDao.getInstance().keyExists(tf.getFacilityKey());
if (result == false) {
result = tf.getUserSetThis() == null;
}
// throw exception if it is a FacilityAvailability that is maybe
// available
if (result == false) {
try {
FacilityAvailability tester = tf;
if (tester.isMaybeAvailable()) {
result = true;
}
} catch (Exception e) {
}
}
return result;
}
/** {@inheritDoc} */
@Override
protected void logAndThrowDataIntegrityViolationException(FacilityAvailability dataholder) throws DataIntegrityViolationException {
String mess = "insert fail on " + dataholder + ".";
DataIntegrityViolationException ex = new DataIntegrityViolationException(mess);
FamLog.logException(FacilityDao.class, ex, mess, 200904241155l);
throw ex;
}
/** {@inheritDoc} */
@Override
protected void logInsert(FacilityAvailability dataholder) {
FamLog.logInfo(FacilityDao.class, "insert " + dataholder + ".", 200904241155l);
}
/** {@inheritDoc} */
@Override
protected void logUpdate(FacilityAvailability dataholder) {
FamLog.logInfo(FacilityDao.class, "update " + dataholder + ".", 200911181627l);
}
/** {@inheritDoc} */
@Override
protected void setIdToNextId(FacilityAvailability dataholder) {
if (idToSet == null) {
idToSet = this.getBiggestId();
}
dataholder.setFacilityAvailabilityId(++idToSet);
}
/**
* return the current sudden failure on given facility or null, if nothing
* exists.
*
* @param d
* facility the sudden failure is for
* @return the current sudden failure on given facility or null, if nothing
* exists.
*/
public FacilityAvailability getCurrentSuddenFailure(Facility d) {
FacilityAvailability result = null;
List<FacilityAvailability> das = FamDaoProxy.facilityDao().getFacilityAvailabilities(d);
for (FacilityAvailability da : das) {
if (da.isNotAvailableBecauseOfSuddenFailure() && !da.getBasePeriodOfTime().endsInPast()) {
result = da;
break;
}
}
return result;
}
/**
* stop the current sudden failure on the given facility. if the facility has
* no sudden failure or does not exist, do nothing here. on updating the
* sudden failure, the user is set to the given user. timestamp set is set
* to current time stamp. the end of the base time for the facility
* availability is set to now.
*
* @param d
* the current sudden failure is stop of
* @param userSetThis
* set as the user that stops the current sudden failure
*/
public void stopCurrentSuddenFailure(Facility d, User userSetThis) {
FacilityAvailability da = FamDaoProxy.facilityDao().getCurrentSuddenFailure(d);
if (da != null) { // bad request
TimeFrame base = da.getBasePeriodOfTime();
base.setEnd(Calendar.getInstance());
da.setBasePeriodOfTime(base);
da.setUserSetThis(userSetThis);
da.setTimeStampSet(new Date());
da.update();
}
}
/**
* return the biggest id set in container. if no object / row there, return
* 0.
*
* @return the biggest id set in container.
*/
protected abstract long getBiggestId();
/**
* return all {@link FacilityAvailability}s and its parents of given
* facilityKey. the result is unmerged and with parents.
*
* @param facilityKey
* of returned {@link FacilityAvailability}s. parents are
* returned as well.
* @return all {@link FacilityAvailability}s and its parents of given
* facilityKey.
*/
public List<FacilityAvailability> getFacilityAvailabilitiesFollowingParents(String facilityKey) {
return this.getFacilityAvailabilitiesFollowingParents(FacilityConfigDao.facility(facilityKey));
}
/**
* return all {@link FacilityAvailability}s and its parents of given
* facilityKey. the result is unmerged and with parents.
*
* @param facility
* of returned {@link FacilityAvailability}s. parents are
* returned as well.
* @return all {@link FacilityAvailability}s and its parents of given
* facilityKey.
*/
private List<FacilityAvailability> getFacilityAvailabilitiesFollowingParents(Facility facility) {
List<FacilityAvailability> result = new ArrayList<FacilityAvailability>(this.getFacilityAvailabilities(facility));
if (facility.hasParent()) {
result.addAll(this.getFacilityAvailabilitiesFollowingParents(facility.getParentFacility()));
}
return result;
}
/**
* return all {@link FacilityAvailability}s and its parents of given
* facilityKey.
*
* all time frames are merged by facilities. the results will have lost the
* {@link FacilityAvailability#timeStampSet}.
*
* children have higher priority then parents. if the parent say "available"
* and the child say "not available", the result will say "not available".
*
* @param fromTo
* get only {@link FacilityAvailability}s overlapping this
* {@link TimeFrame}.
* @param facilityKey
* of returned {@link FacilityAvailability}s. parents are
* returned as well.
* @return all {@link FacilityAvailability}s and its parents of given
* facilityKey.
*/
public List<FacilityAvailability> getFacilityAvailabilitiesMergedByFacilities(TimeFrame fromTo, String facilityKey) {
// get all FacilityAvailabilitys of given facilityKey
List<FacilityAvailability> mergeThis = FamDaoProxy.facilityDao().getFacilityAvailabilitiesIgnoreParents(fromTo, facilityKey);
// add priority (in wrong order first)
List<String> reverseOrderFacilityPriority = new ArrayList<String>();
reverseOrderFacilityPriority.add(facilityKey);
// do that with parent and parent's parent
while (FacilityConfigDao.getInstance().hasParentFacility(facilityKey)) {
String parentKey = FacilityConfigDao.getInstance().getParentFacilityKey(facilityKey);
List<FacilityAvailability> dasParents = FamDaoProxy.facilityDao().getFacilityAvailabilitiesIgnoreParents(fromTo, parentKey);
reverseOrderFacilityPriority.add(parentKey);
mergeThis.addAll(dasParents);
facilityKey = parentKey;
}
// switch priority order
List<String> orderedFacilityPriority = new ArrayList<String>();
for (int i = reverseOrderFacilityPriority.size() - 1; i >= 0; i--) {
orderedFacilityPriority.add(reverseOrderFacilityPriority.get(i));
}
// get result
return FacilityAvailabilityMerger.getMergedByFacilities(mergeThis, fromTo, orderedFacilityPriority);
}
/**
* return all {@link FacilityAvailability}s for facility and of given day.
* {@link FacilityAvailability}s are merged.
*
* @see FacilityDao#getFacilityAvailabilitiesMergedByFacilities(de.knurt.heinzelmann.util.time.TimeFrame,
* java.lang.String)
* @param c
* day of interest
* @param facility
* of interest
* @return all {@link FacilityAvailability}s for facility and of given day.
*/
public List<FacilityAvailability> getFacilityAvailabilitiesOfDay(Calendar c, Facility facility) {
TimeFrame tf = SimpleTimeFrame.getDay(c);
return this.getFacilityAvailabilitiesMergedByFacilities(tf, facility.getKey());
}
/**
* return all facility availabilities set for the given facility.
*
* @param facility
* given.
* @return all facility availabilities set for the given facility.
*/
public List<FacilityAvailability> getFacilityAvailabilities(Facility facility) {
return this.getFacilityAvailabilities(facility.getKey());
}
/**
* return a list of keys representing the facilities the user is responsible
* for. if the user is unknown for responsibilities, return
* <code>null</code>:
*
* @param user
* a list of keys representing the facilities is returned of.
* @return a list of keys representing the facilities the user is
* responsible for.
*/
public abstract List<String> getFacilityKeysUserIsResponsibleFor(User user);
/**
* return <code>true</code> if the user has at least responsibility for one
* facility. otherwise return <code>false</code>
*
* @param user
* to check
* @return true if the user has at least responsibility for one facility.
*/
public abstract boolean hasResponsibilityForAFacility(User user);
/**
* return a list of bookable facilities, the user is responsible for or an
* empty array, if the user does not have any responsibilities for a
* bookable facility.
*
* @param user
* of interest
* @return a list of bookable facilities, the user is responsible for or
* null.
*/
public abstract List<Facility> getBookableFacilitiesUserIsResponsibleFor(User user);
/**
* return a list of facilities, the user is responsible for or an empty
* array, if the user does not have any responsibilities for a facility.
*
* @param user
* of interest
* @return a list of facilities, the user is responsible for or null.
*/
public abstract List<Facility> getFacilitiesUserIsResponsibleFor(User user);
/**
* set the responsibilities of the given user to the given facilities
*
* @param user
* is responsible for the given facilities
* @param facilities
* the given user is responsible for
* @return true if update succeeded
*/
public abstract boolean updateResponsibility(User newUser, List<Facility> facilities);
/**
* return true, if the given user has the responsibility for the given
* facility
*
* @param user
* to check
* @param facility
* to check
* @return true, if the given user has the responsibility for the given
* facility
*/
public boolean hasResponsibilityForFacility(User user, Facility facility) {
boolean result = false;
List<Facility> facilities = this.getFacilitiesUserIsResponsibleFor(user);
for (Facility candidate : facilities) {
if (candidate.getKey().equals(facility.getKey())) {
result = true;
break;
}
}
return result;
}
}