/*
* Copyright 2013-2017 Simba Open Source
*
* 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.simbasecurity.core.domain.condition;
import java.text.ParseException;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;
import javax.persistence.Transient;
import org.hibernate.annotations.AccessType;
import org.simbasecurity.core.domain.ConditionEntity;
import org.simbasecurity.core.service.AuthorizationRequestContext;
import org.simbasecurity.core.spring.quartz.ExtendedCronExpression;
/**
* Represents a sequence of time intervals. The condition is satisfied if the
* current time is inside any of intervals. The sequence is defined by two cron
* expressions - startCondition and endCondition. startCondition is the sequence
* of time moments in which the intervals start. endCondition is the sequence of
* time moments in which the intervals end. So, for this definition to be
* correct it is required that for every start moment it should be an end moment
* in such a way that intervals don't overlap. Right now the rule above is not
* validated.
* <p/>
* Any valid CRON expressions are supported. See <a
* href="http://www.quartz-scheduler.org/docs/tutorials/crontrigger.html">Quartz
* expressions help</a> for a complete guide.
*/
@Entity
@Table(name = "SIMBA_TIME_CONDITION")
@PrimaryKeyJoinColumn(name = "CONDITION_ID")
@AccessType("property")
public class TimeCondition extends ConditionEntity {
private static final long serialVersionUID = 1812282413540572395L;
private String startCondition;
private String endCondition;
@Transient
private ExtendedCronExpression startExpression;
@Transient
private ExtendedCronExpression endExpression;
public TimeCondition() {
}
public TimeCondition(String startCondition, String endCondition) {
this.setStartCondition(startCondition);
this.setEndCondition(endCondition);
}
@Column(name = "START_EXPR")
public String getStartCondition() {
return startCondition;
}
public void setStartCondition(String startCondition) {
try {
this.startExpression = new ExtendedCronExpression(startCondition);
} catch (ParseException e) {
throw new IllegalArgumentException(e);
}
this.startCondition = startCondition;
}
@Column(name = "END_EXPR")
public String getEndCondition() {
return endCondition;
}
public void setEndCondition(String endCondition) {
try {
this.endExpression = new ExtendedCronExpression(endCondition);
} catch (ParseException e) {
throw new IllegalArgumentException(e);
}
this.endCondition = endCondition;
}
@Override
public boolean conditionApplies(AuthorizationRequestContext context) {
return isInInterval(context.getTime());
}
boolean isInInterval(long timestamp) {
Date checkDate = new Date(timestamp);
Date beforeDate = startExpression.getTimeBefore(checkDate);
Date afterDate = endExpression.getTimeAfter(beforeDate);
return beforeDate != null && afterDate != null
&& !checkDate.before(beforeDate) && !checkDate.after(afterDate);
}
@Override
public long getExpirationTimestamp(AuthorizationRequestContext context) {
return getExpirationTimestamp(context.getTime());
}
long getExpirationTimestamp(long timestamp) {
ExtendedCronExpression expr = isInInterval(timestamp) ? endExpression : startExpression;
Date oneMillisecondBeforeTimestamp = new Date(timestamp - 1);
return expr.getTimeAfter(oneMillisecondBeforeTimestamp).getTime();
}
}