/**
* Helios, OpenSource Monitoring
* Brought to you by the Helios Development Group
*
* Copyright 2007, Helios Development Group and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*
*/
package org.helios.collector.jdbc.binding.provider;
import org.helios.collector.jdbc.binding.binder.Binder;
import org.helios.collector.jdbc.binding.binder.IBinder;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
/**
* <p>Title: SysTimeProvider</p>
* <p>Description: A bind variable provider to supply the current and relative time stamps </p>
* <p>Company: Helios Development Group</p>
* @author Whitehead (whitehead.nicholas@gmail.com)
* @version $LastChangedRevision$
* $HeadURL$
* $Id$
*/
@BindVariableProvider(defaultBinder=SysTimeProvider.class, tokenKey="SysTime")
@Binder(name="SysTime")
public class SysTimeProvider extends AbstractBindVariableProvider implements IBinder {
public static final String DEFAULT_FORMAT = "MM/dd/yyyy hh:mm:ss a";
protected String dateFormat = DEFAULT_FORMAT;
protected Set<TimeAdjust> adjusts = new HashSet<TimeAdjust>();
protected long offset = 0;
protected ThreadLocal<SimpleDateFormat> formatter = new ThreadLocal<SimpleDateFormat>() {
protected synchronized SimpleDateFormat initialValue() {
return new SimpleDateFormat(dateFormat);
}
};
/**
* Configures this instace of the provider.
* @param config
* @see org.helios.collectors.jdbc.binding.provider.AbstractBindVariableProvider#configure(java.lang.String)
*/
@Override
public void configureProvider(String config) throws BindProviderConfigurationException {
Matcher m = ProviderToken.BIND_VAR_PATTERN.matcher(config);
while(m.find()) {
TimeAdjust ta = new TimeAdjust(m.group(1), Integer.parseInt(m.group(2)), m.group(3));
offset = offset + ta.getOffSet();
String format = m.group(4);
if(format!=null) {
dateFormat = format;
formatter = new ThreadLocal<SimpleDateFormat>() {
protected synchronized SimpleDateFormat initialValue() {
return new SimpleDateFormat(dateFormat);
}
};
}
}
}
/**
* Calculates the current time stamp plus or minus all the adjusted times.
* @return the adjusted time.
*/
@Override
public Object getValue() {
return System.currentTimeMillis() + offset;
}
/**
* Does not support setValue.
*/
@Override
public void setValue(Object o) {}
/**
* Executes a bind against a prepared statement.
* @param ps The prepared statement to invoke the bind against.
* @param bindSequence The bind sequence.
* @return The final bind sequence executed by this bind call. Normally, this would be the same as <code>bindSequence</code>.
* @throws SQLException
*/
public int bind(PreparedStatement ps, int bindSequence, Object value) throws SQLException {
ps.setTimestamp(bindSequence, new Timestamp((Long)value));
return bindSequence;
}
/**
* Executes a token substitution against a sql statement for the passed bind token, replacing the token with the provider supplied literal.
* Intended to support binding-like operations when using drivers that do not support <code>PreparedStatements</code> and/or bind variables.
* @param sql The tokenized sql statement
* @param bindToken The bind token to replace with a literal binding.
* @return The substituted sql statement.
* @throws SQLException
*/
public CharSequence bind(CharSequence sql, String bindToken, Object value) throws SQLException {
try {
Date date = new Date((Long)value);
String dateStr = "'" + formatter.get().format(date) + "'";
if(log.isDebugEnabled()) log.debug("Replacing [" + bindToken + "] with [" + dateStr + "]");
return sql.toString().replace(bindToken, dateStr);
} catch (Exception e) {
throw new SQLException("" + e);
}
}
/**
* @param config
* @throws BindProviderConfigurationException
* @see org.helios.collectors.jdbc.binding.binder.IBinder#configureBinder(java.lang.String)
*/
public void configureBinder(String config) throws BindProviderConfigurationException {
}
}
/**
* <p>Title: TimeAdjust</p>
* <p>Description: Value class to capture a set of time modifiers.</p>
* <p>Company: Helios Development Group</p>
* @author Whitehead (whitehead.nicholas@gmail.com)
* @version $LastChangedRevision$
* $HeadURL$
* $Id$
*/
class TimeAdjust {
/** */
protected String sign = null;
/** */
protected int size = 0;
/** */
protected String unit = null;
/**
* Creates a new TimeAdjust
* @param sign The sign (+ or -)
* @param size The size of the adjust
* @param unit The unit of the adjust
*/
public TimeAdjust(String sign, int size, String unit) {
this.sign = sign;
this.size = size;
this.unit = unit;
}
public long getOffSet() {
long offset = 0;
if(unit.equalsIgnoreCase("ms")) {
offset = size;
} else if(unit.equalsIgnoreCase("s")) {
offset = TimeUnit.MILLISECONDS.convert(size, TimeUnit.SECONDS);
} else if(unit.equalsIgnoreCase("m")) {
offset = TimeUnit.MILLISECONDS.convert(size, TimeUnit.SECONDS)*60;
} else if(unit.equalsIgnoreCase("h")) {
offset = TimeUnit.MILLISECONDS.convert(size, TimeUnit.SECONDS)*60*60;
} else if(unit.equalsIgnoreCase("d")) {
offset = TimeUnit.MILLISECONDS.convert(size, TimeUnit.SECONDS)*60*60*24;
} else {
throw new RuntimeException("The unit [" + unit +"] is not recognized");
}
if(sign.equals("-")) {
return offset*-1;
} else if(sign.equals("+")) {
return offset;
} else {
throw new RuntimeException("The sign [" + sign +"] is not recognized");
}
}
/**
* @return
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((sign == null) ? 0 : sign.hashCode());
result = prime * result + size;
result = prime * result + ((unit == null) ? 0 : unit.hashCode());
return result;
}
/**
* @param obj
* @return
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
TimeAdjust other = (TimeAdjust) obj;
if (sign == null) {
if (other.sign != null)
return false;
} else if (!sign.equals(other.sign))
return false;
if (size != other.size)
return false;
if (unit == null) {
if (other.unit != null)
return false;
} else if (!unit.equals(other.unit))
return false;
return true;
}
}