all compile:
JAVA_HOME=${jdk_prefix} \
${ant_prefix}/bin/ant -Dno.deps=yes -DstageDir=${stagedir} \
+ -Dfile.reference.commons-lang.jar=${commons-lang_jar} \
-Dreference.jobid-api-java.jar=${stagedir}/share/java/jobid-api-java.jar \
-Dreference.trustmanager.jar=${trustmanager_prefix}/share/java/glite-security-trustmanager.jar \
-Daxis.classpath=`ls ${axis_prefix}/lib/*.jar | tr '\012' :`
includes=**
jar.compress=false
javac.classpath=\
+ ${file.reference.commons-lang.jar}:\
${axis.classpath}:\
${reference.jobid-api-java.jar}:\
${reference.trustmanager.jar}:\
--- /dev/null
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.glite.lb;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+
+/**
+ * this class handles communication with LB server (reads messages it sends)
+ *
+ * @author Kopac
+ */
+public class ILProtoReceiver {
+
+ private Socket socket = null;
+ private InputStream inStream = null;
+ private OutputStream outStream = null;
+ private static final String magicWord = "6 michal";
+
+ /**
+ * construcor initializes the class' socket, inStream and outStream attributes
+ *
+ * @param socket an SSLSocket
+ * @throws java.io.IOException
+ */
+ public ILProtoReceiver(Socket socket) throws IOException {
+ this.socket = socket;
+ inStream = this.socket.getInputStream();
+ outStream = this.socket.getOutputStream();
+ }
+
+ /**
+ * this method reads from the inpuStream of the provided socket, checks for
+ * the magic word and returns relevant info
+ *
+ * @return a String containing third line of the inputStream data, without
+ * the info about its length
+ * @throws IOException
+ */
+ public String receiveMessage() throws IOException{
+ byte[] b = new byte[17];
+ int i = 0;
+ //read in and convert size of the message
+ if(inStream.read(b, 0, 17) == -1) {
+ return null;
+ } else {
+ String test = new String(b);
+ test.trim();
+ int length = Integer.parseInt(test);
+ byte[] notification = new byte[length];
+ //read in the rest of the message
+ int j = 0;
+ while(i != length || j == -1) {
+ j = inStream.read(notification, i, length);
+ i=i+j;
+ }
+ String retString = checkWord(notification);
+ if(retString == null) return null;
+ else
+ //return
+ return retString.split(" ", 2)[1];
+ }
+ }
+
+ /**
+ * private method that checks, if the magic word is present in the notification
+ *
+ * @param notification a notification without the line specifying its length
+ * @return null, if the word is not there, the last line of the notification,
+ * again without its length specification, otherwise
+ */
+ private String checkWord(byte[] notification) {
+ int i = 0;
+ while(notification[i] != '\n') {
+ i++;
+ }
+ String word = new String(notification, 0, i+1);
+ word.trim();
+ if(!word.equals(magicWord)) {
+ return null;
+ } else {
+ return new String(notification, i+1, notification.length - i + 1);
+ }
+ }
+
+ /**
+ * this method encodes and sends a reply to the interlogger via the socket's
+ * outputStream
+ *
+ * @param errCode errCode of the calling
+ * @param minErrCode minimum available errcode
+ * @param message message for the interlogger - could be any String
+ * @throws IOException
+ */
+ public void sendReply(int errCode, int minErrCode, String message) throws IOException {
+ byte[] errByte = (new String()+errCode).getBytes();
+ byte[] minErrByte = (new String()+minErrCode).getBytes();
+ byte[] msgByte = message.getBytes();
+ int length = errByte.length + minErrByte.length + msgByte.length;
+ byte[] lengthByte = (new String()+length).getBytes();
+ int numberOfSpaces = 17 - lengthByte.length;
+ byte[] returnByte = new byte[length+17];
+ int i = 0;
+ while(i < numberOfSpaces-1) {
+ returnByte[i] = ' ';
+ i++;
+ }
+ returnByte = putByte(returnByte, lengthByte, numberOfSpaces);
+ returnByte[16] = '\n';
+ returnByte = putByte(returnByte, errByte, 17);
+ returnByte = putByte(returnByte, minErrByte, 16 + errByte.length);
+ returnByte = putByte(returnByte, msgByte, 16 + errByte.length + minErrByte.length);
+ outStream.write(returnByte);
+ }
+
+ /**
+ * appends a byte array to the end of an existing byte array
+ *
+ * @param arrayToFill array to be filled
+ * @param filler array to be appended
+ * @param start starting offset of the first array, from which the second
+ * array should be appended
+ * @return the resulting byte array
+ */
+ private byte[] putByte(byte[] arrayToFill, byte[] filler, int start) {
+ for(int i = start; i < filler.length + start; i++) {
+ int j = 0;
+ arrayToFill[i] = filler[j];
+ j++;
+ }
+ return arrayToFill;
+ }
+}
--- /dev/null
+
+package org.glite.lb;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.glite.jobid.Jobid;
+import org.glite.lb.Event;
+import org.glite.wsdl.types.lb.JobFlagsValue;
+import org.glite.wsdl.types.lb.JobStatus;
+import org.glite.wsdl.types.lb.QueryAttr;
+import org.glite.wsdl.types.lb.QueryConditions;
+import org.glite.wsdl.types.lb.QueryOp;
+import org.glite.wsdl.types.lb.QueryRecValue;
+import org.glite.wsdl.types.lb.QueryRecord;
+
+/**
+ * Class encapsulating the job info stored in the L&B database.
+ *
+ * This class is the primary interface for getting information about
+ * job stored in the L&B database. It is constructed from known job
+ * id, which uniquely identifies the job as well as the bookkeeping
+ * server where the job data is stored. The Job class provides methods
+ * for obtaining the data from the bookkeeping server.
+ *
+ * @author Tomas Kramec, 207545@mail.muni.cz
+ */
+public class Job {
+
+ private Jobid jobId;
+ private ServerConnection serverConnection;
+
+ /**
+ * Constructor initializes the job as empty, not representing anything.
+ */
+ public Job() {
+ }
+
+ /**
+ * Constructor from job id and bookkeeping server connection.
+ * Initializes the job to obtain information for the given job id.
+ *
+ * @param jobId The job id of the job this object wil represent.
+ * @param serverConnection ServerConnection object providing methods
+ * for obtaining the data from the bookkeeping server.
+ */
+ public Job(Jobid jobId, ServerConnection serverConnection) {
+ if (jobId == null) throw new IllegalArgumentException("jobId cannot be null");
+ if (serverConnection == null) throw new IllegalArgumentException("server cannot be null");
+
+ this.jobId = jobId;
+ this.serverConnection = serverConnection;
+ }
+
+ /**
+ * Constructor from job id and bookkeeping server connection.
+ * Initializes the job to obtain information for the given job id.
+ *
+ * @param jobId The job id of the job this object wil represent.
+ * @param serverConnection ServerConnection object providing methods
+ * for obtaining the data from the bookkeeping server.
+ */
+ public Job(String jobId, ServerConnection serverConnection) {
+ this(new Jobid(jobId), serverConnection);
+ }
+
+ /**
+ * Gets this job ID.
+ *
+ * @return jobId
+ */
+ public Jobid getJobId() {
+ return jobId;
+ }
+
+ /**
+ * Sets the jobId to this job.
+ *
+ * @param jobId
+ */
+ public void setJobId(Jobid jobId) {
+ if (jobId == null) throw new IllegalArgumentException("jobId");
+
+ this.jobId = jobId;
+ }
+
+ /**
+ * Gets server connection.
+ *
+ * @return serverConnection
+ */
+ public ServerConnection getServer() {
+ return serverConnection;
+ }
+
+ /**
+ * Sets server connection instance to this job.
+ *
+ * @param serverConnection
+ */
+ public void setServer(ServerConnection serverConnection) {
+ if (serverConnection == null) throw new IllegalArgumentException("server");
+
+ this.serverConnection = serverConnection;
+ }
+
+
+ /**
+ * Return job status.
+ * Obtains the job status (as JobStatus) from the bookkeeping server.
+ *
+ * @param flags Specify details of the query. Determines which status
+ * fields are actually retrieved.
+ * Possible values:<ol>
+ * <li type="disc">CLASSADS - Include the job description in the query result.</li>
+ * <li type="disc">CHILDREN - Include the list of subjob id's in the query result.</li>
+ * <li type="disc">CHILDSTAT - Apply the flags recursively to subjobs.</li>
+ * <li type="disc">CHILDHIST_FAST - Include partially complete histogram of child job states.</li>
+ * <li type="disc">CHILDHIST_THOROUGH - Include full and up-to date histogram of child job states.</li>
+ * </ol>
+ *
+ * @return Status of the job.
+ * @throws LBException If some communication or server problem occurs.
+ */
+ public JobStatus getStatus(JobFlagsValue[] flags) throws LBException {
+ if (serverConnection == null)
+ throw new IllegalStateException("serverConnection is null, please set it");
+ if (jobId == null)
+ throw new IllegalStateException("jobId is null, please set it");
+ try {
+ return serverConnection.jobState(jobId.toString(), flags);
+ } catch (LBException ex) {
+ throw new LBException(ex);
+ }
+ }
+
+ /**
+ * Return all events corresponding to this job.
+ * Obtains all events corresponding to the job that are stored
+ * in the bookkeeping server database.
+ * <p>
+ * Default value for logging level is SYSTEM. If needed, it can be changed
+ * by calling <b>setEventLoggingLevel(Level loggingLevel)</b> method
+ * on the serverConnection attribute of this class.
+ * </p>
+ *
+ * @return events List of events (of type Event).
+ * @throws LBException If some communication or server problem occurs.
+ */
+ public List<Event> getEvents() throws LBException {
+ if (serverConnection == null)
+ throw new IllegalStateException("serverConnection is null, please set it");
+ if (jobId == null)
+ throw new IllegalStateException("jobId is null, please set it");
+
+ QueryRecValue jobIdValue = new QueryRecValue(null, jobId.toString(), null);
+ QueryRecord[] jobIdRec = new QueryRecord[] {new QueryRecord(QueryOp.EQUAL, jobIdValue, null)};
+ QueryConditions[] query = new QueryConditions[]{new QueryConditions(QueryAttr.JOBID, null, null, jobIdRec)};
+ QueryRecValue levelValue = new QueryRecValue(serverConnection.getEventLoggingLevel().getInt()+1, null, null);
+ QueryRecord[] levelRec = new QueryRecord[] {new QueryRecord(QueryOp.LESS, levelValue, null)};
+ QueryConditions[] queryEvent = new QueryConditions[]{new QueryConditions(QueryAttr.LEVEL, null, null, levelRec)};
+ List<QueryConditions> queryList = new ArrayList<QueryConditions>();
+ queryList.add(query[0]);
+ List<QueryConditions> queryEventList = new ArrayList<QueryConditions>();
+ queryEventList.add(queryEvent[0]);
+
+ return serverConnection.queryEvents(queryList, queryEventList);
+ }
+}
--- /dev/null
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.glite.lb;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import javax.xml.rpc.ServiceException;
+import org.apache.axis.AxisProperties;
+import org.glite.wsdl.services.lb.LoggingAndBookkeepingLocator;
+import org.glite.wsdl.services.lb.LoggingAndBookkeepingPortType;
+
+/**
+ *
+ */
+public class LBCredentials {
+
+ public LBCredentials(String proxy, String caFiles) {
+ if (proxy == null) throw new IllegalArgumentException("Proxy cannot be null");
+ if (caFiles == null) throw new IllegalArgumentException("caFiles cannot be null");
+
+ System.setProperty(org.glite.security.trustmanager.ContextWrapper.CREDENTIALS_PROXY_FILE, proxy);
+ System.setProperty(org.glite.security.trustmanager.ContextWrapper.CA_FILES, caFiles);
+ System.setProperty(org.glite.security.trustmanager.ContextWrapper.SSL_PROTOCOL, "SSLv3");
+ AxisProperties.setProperty("axis.socketSecureFactory","org.glite.security.trustmanager.axis.AXISSocketFactory");
+ }
+
+ public LBCredentials(String userCert, String userKey, String userPass, String caFiles) {
+ if (userCert==null || userKey==null || userPass==null || caFiles==null)
+ throw new IllegalArgumentException("One of the parameters was null");
+
+ System.setProperty(org.glite.security.trustmanager.ContextWrapper.CREDENTIALS_CERT_FILE,userCert);
+ System.setProperty(org.glite.security.trustmanager.ContextWrapper.CREDENTIALS_KEY_FILE,userKey);
+ System.setProperty(org.glite.security.trustmanager.ContextWrapper.CREDENTIALS_KEY_PASSWD,userPass);
+ System.setProperty(org.glite.security.trustmanager.ContextWrapper.CA_FILES, caFiles);
+ System.setProperty(org.glite.security.trustmanager.ContextWrapper.SSL_PROTOCOL, "SSLv3");
+ AxisProperties.setProperty("axis.socketSecureFactory","org.glite.security.trustmanager.axis.AXISSocketFactory");
+ }
+
+ protected LoggingAndBookkeepingPortType getStub(String server) throws LBException {
+ if (server == null)
+ throw new IllegalArgumentException("Server cannot be null");
+ try {
+ URL queryServerAddress = new URL(server);
+ int port = queryServerAddress.getPort();
+ if (port < 1 || port > 65535) {
+ throw new IllegalArgumentException("port");
+ }
+ if (!queryServerAddress.getProtocol().equals("https")) {
+ throw new IllegalArgumentException("wrong protocol");
+ }
+ LoggingAndBookkeepingLocator loc = new LoggingAndBookkeepingLocator();
+ return loc.getLoggingAndBookkeeping(queryServerAddress);
+ } catch (ServiceException ex) {
+ throw new LBException(ex);
+ } catch (MalformedURLException ex) {
+ throw new LBException(ex);
+ }
+ }
+
+}
package org.glite.lb;
public class LBException extends Exception {
- public LBException(Throwable e) {
+
+ public LBException(Throwable e) {
super(e);
- }
+ }
+
}
--- /dev/null
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.glite.lb;
+
+import java.io.IOException;
+import java.io.StringReader;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFactory;
+import org.apache.commons.lang.StringEscapeUtils;
+import org.glite.wsdl.types.lb.JobStatus;
+import org.w3c.dom.Document;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * this class parses the received message into a readable format
+ *
+ * @author Kopac
+ */
+public class NotifParser {
+
+ Document doc = null;
+ String header = null;
+
+
+ /**
+ * constructor takes a notification in String format and parses it into a String
+ * containing the header and an XML doc
+ *
+ * @param notif the string with notification in it
+ * @throws javax.xml.parsers.ParserConfigurationException
+ * @throws org.xml.sax.SAXException
+ * @throws java.io.IOException
+ */
+ public NotifParser(String notif) throws ParserConfigurationException, SAXException, IOException {
+ String[] splitString = notif.split("DG.NOTIFICATION.JOBSTAT=\"", 2);
+ header = splitString[0];
+ doc = createXML(splitString[1]);
+ }
+
+ /**
+ * this method reads through an XML document using XPath expressions and
+ * fills an instance of JobStatus, which it then returns
+ * this is done using automatically generated code
+ *
+ * @param notification an array of bytes containing the raw notification
+ * @return a Jobstatus instance
+ */
+ public JobStatus getJobInfo()
+ throws ParserConfigurationException, SAXException, IOException {
+ JobStatus status = new JobStatus();
+ //TODO: insert automated code creation
+ status.setJobId(evaluateXPath("//jobId").item(0).getTextContent());
+ status.setOwner(evaluateXPath("//owner").item(0).getTextContent());
+ return status;
+ }
+
+ /**
+ * this method returns id of the notification
+ *
+ * @return notif id
+ */
+ public String getNotifId() {
+ String halfHeader = header.split("DG.NOTIFICATION.NOTIFID=\"")[1];
+ return halfHeader.substring(0, halfHeader.indexOf("\""));
+ }
+
+ /**
+ * a method for handling xpath queries
+ *
+ * @param xpathString xpath expression
+ * @return the result nodelist
+ */
+ private NodeList evaluateXPath(String xpathString) {
+ try {
+ XPathFactory xfactory = XPathFactory.newInstance();
+ XPath xpath = xfactory.newXPath();
+ XPathExpression expr = xpath.compile(xpathString);
+ return (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
+ } catch (XPathExpressionException ex) {
+ ex.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * this method creates an XML document out of a provided String
+ * note that the string has to be a valid escaped XML document representation,
+ * otherwise the process will fail
+ *
+ * @param body a String containing an XML document
+ * @return an XML document in the Document format
+ * @throws javax.xml.parsers.ParserConfigurationException
+ * @throws org.xml.sax.SAXException
+ * @throws java.io.IOException
+ */
+ private Document createXML(String body) throws ParserConfigurationException, SAXException, IOException {
+ String removed = body.substring(0, body.length()-1);
+ String parsed = StringEscapeUtils.unescapeXml(removed);
+ //this code removes hexadecimal references from the string (couldn't find
+ //a suitable parser for this)
+ StringBuilder build = new StringBuilder(parsed);
+ int j = build.indexOf("%");
+ while(j > 0) {
+ if(build.charAt(j-1) == '>') {
+ build.delete(j, j+3);
+ if(build.charAt(j) == '<') {
+ j = build.indexOf("%");
+ }
+ } else {
+ j = build.indexOf("%", j+1);
+ }
+ }
+ parsed = build.toString();
+ //ends here
+ DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+ return factory.newDocumentBuilder().parse(new InputSource(new StringReader(parsed)));
+ }
+}
--- /dev/null
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.glite.lb;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.rmi.RemoteException;
+import java.security.KeyManagementException;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Calendar;
+import java.util.Date;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.rpc.holders.CalendarHolder;
+import org.glite.jobid.Jobid;
+import org.glite.lb.SSL;
+import org.glite.wsdl.services.lb.LoggingAndBookkeepingPortType;
+import org.glite.wsdl.types.lb.JobFlagsValue;
+import org.glite.wsdl.types.lb.JobStatus;
+import org.glite.wsdl.types.lb.QueryConditions;
+import org.xml.sax.SAXException;
+
+/**
+ * This class handles all communication comming from the client toward the server.
+ * it uses methods generated from .wsdl description files.
+ * note that each instance of this class is dedicated to a single port. Different
+ * port means a new instance has to be created
+ *
+ * @author Kopac
+ */
+public class Notification {
+
+ private int port = 0;
+ private Socket socket = null;
+ private static String keyStore;
+ private String notifId;
+ private LoggingAndBookkeepingPortType stub;
+ private LBCredentials lbCredent;
+
+ /**
+ * constructor sets the local port number
+ *
+ * @param port number of the local port the notification is bound to
+ * @param lbCredent instance of class that handles SSL authentication
+ */
+ public Notification(int port, LBCredentials lbCredent) {
+ this.port = port;
+ this.lbCredent = lbCredent;
+ }
+
+ /**
+ * a private method used to create a unique ID for a new notification
+ *
+ * @param host hostname
+ * @return String containing the unique ID
+ */
+ private String makeId(String host) {
+ StringBuilder returnString = new StringBuilder();
+ returnString.append(host);
+ Jobid jobid = new Jobid(returnString.toString(), port);
+ returnString.append("/NOTIF:");
+ returnString.append(jobid.getUnique());
+ return returnString.toString();
+ }
+
+ /**
+ * returns ID of the latest received notification
+ *
+ * @return notifID
+ */
+ public String getNotifid() {
+ return notifId;
+ }
+
+ /**
+ * private method used to recover LB server address from a notif ID
+ *
+ * @param notifId notif ID
+ * @return server address
+ */
+ private String getServer(String notifId) {
+ StringBuilder ret = new StringBuilder(notifId.split("/")[2]);
+ char[] ch = new char[]{ret.charAt(ret.length()-1)};
+ int i = Integer.parseInt(new String(ch)) + 3;
+ ret.replace(ret.length()-1, ret.length()-1, new String()+i);
+ ret.insert(0, "https://");
+ return ret.toString();
+ }
+
+ /**
+ * this method sends a request to the server, to create a new notification.
+ * it's not necessary to provide all the options for this calling, thus
+ * some of the parameters can be null. in that case, the option they correspond to
+ * is not used.
+ *
+ * @param server a String containing the server address (e.g. https://harad.ics.muni.cz:9553).
+ * can't be null
+ * @param conditions an array of QueryConditions, may contain all the possible
+ * conditions for the new notification. can't be null
+ * @param flags an array of JobFlagsValue, may contain all the possible flags
+ * and their values for the new notification.
+ * @param date a Date containing the desired time, the notification will be valid for
+ * note that this option can only be used to shorten the validity span, as the server
+ * checks it and sets the final expiration date to a constant max, should
+ * the provided Date exceed it. may be null
+ * @return a Date holding info on how long the new notification will
+ * be valid for
+ * @throws LBException
+ */
+ public Date newNotif(String server, QueryConditions[] conditions, JobFlagsValue[] flags, Date date) throws LBException {
+ try {
+ CalendarHolder calendarHolder = new CalendarHolder(Calendar.getInstance());
+ if (date != null) {
+ calendarHolder.value.setTime(date);
+ } else {
+ calendarHolder.value.setTime(new Date(System.currentTimeMillis() + 86400000));
+ }
+ stub = lbCredent.getStub(server);
+ String addr = "0.0.0.0:" + port;
+ String id = makeId(server);
+ stub.notifNew(id, addr, conditions, flags, calendarHolder);
+ notifId = id;
+ return calendarHolder.value.getTime();
+ } catch (RemoteException ex) {
+ throw new LBException(ex);
+ }
+ }
+
+ /**
+ * this method drops an existing notification, removing it completely
+ *
+ * @param notifId id of the notification to be dropped
+ * @throws LBException
+ */
+ public void drop(String notifId) throws LBException {
+ try {
+ stub = lbCredent.getStub(getServer(notifId));
+ stub.notifDrop(notifId);
+ } catch (RemoteException ex) {
+ throw new LBException(ex);
+ }
+ }
+
+ /**
+ * this method is used to extend the validity of an existing notification
+ *
+ * @param notifId id of the notification to be refreshed
+ * @param date information about the desired validity duration of the notification
+ * in Date format. may be null (in this case, the maximum possible duration is used).
+ * @throws LBException
+ */
+ public void refresh(String notifId, Date date) throws LBException {
+ try {
+ stub = lbCredent.getStub(getServer(notifId));
+ CalendarHolder holder = new CalendarHolder(Calendar.getInstance());
+ if (date != null) {
+ holder.value.setTime(date);
+ } else {
+ holder.value.setTime(new Date(System.currentTimeMillis() + 86400000));
+ }
+ stub.notifRefresh(notifId, holder);
+ } catch (RemoteException ex) {
+ throw new LBException(ex);
+ }
+ }
+
+ /**
+ * this method is used to bind an existing notification to a different local port
+ * than previously declared
+ *
+ * @param notifId id of th notification
+ * @param date optional attribute, can be used to refresh the notification
+ * @return length of the validity duration of the notification in Date format
+ * @throws LBException
+ */
+ public Date bind(String notifId, Date date) throws LBException {
+ try {
+ stub = lbCredent.getStub(getServer(notifId));
+ String host = InetAddress.getLocalHost().getHostName() + ":" + port;
+ CalendarHolder holder = new CalendarHolder(Calendar.getInstance());
+ if (date != null) {
+ holder.value.setTime(date);
+ } else {
+ holder.value.setTime(new Date(System.currentTimeMillis() + 86400000));
+ }
+ stub.notifBind(notifId, host, holder);
+ return holder.value.getTime();
+ } catch (RemoteException ex) {
+ throw new LBException(ex);
+ } catch (UnknownHostException ex) {
+ throw new LBException(ex);
+ }
+ }
+
+ /**
+ * this method is used to tell the client to start listening for incomming
+ * connections on the local port, with the specified timeout
+ *
+ * @param timeout read timeout
+ * @return comprehensible information, pulled from the received message
+ * @throws LBException
+ */
+ public JobStatus receive(int timeout) throws LBException {
+ SSL ssl = new SSL();
+ ssl.setProxy(keyStore);
+ ILProtoReceiver receiver = null;
+ String received = null;
+ try {
+ if(socket == null) {
+ socket = ssl.accept(port, timeout);
+ }
+ receiver = new ILProtoReceiver(socket);
+ if((received = receiver.receiveMessage()) == null) {
+ socket = ssl.accept(port, timeout);
+ receiver = new ILProtoReceiver(socket);
+ received = receiver.receiveMessage();
+ }
+ receiver.sendReply(0, 0, "success");
+ NotifParser parser = new NotifParser(received);
+ notifId = parser.getNotifId();
+ return parser.getJobInfo();
+ } catch (IOException ex) {
+ throw new LBException(ex);
+ } catch (KeyManagementException ex) {
+ throw new LBException(ex);
+ } catch (KeyStoreException ex) {
+ throw new LBException(ex);
+ } catch (NoSuchAlgorithmException ex) {
+ throw new LBException(ex);
+ } catch (ParserConfigurationException ex) {
+ throw new LBException(ex);
+ } catch (SAXException ex) {
+ throw new LBException(ex);
+ }
+ }
+}
--- /dev/null
+/*
+ * To change this template, choose Tools | Templates
+ * and open the template in the editor.
+ */
+
+package org.glite.lb;
+
+import java.util.Date;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.glite.wsdl.types.lb.JobStatus;
+import org.glite.wsdl.types.lb.QueryAttr;
+import org.glite.wsdl.types.lb.QueryConditions;
+import org.glite.wsdl.types.lb.QueryOp;
+import org.glite.wsdl.types.lb.QueryRecValue;
+import org.glite.wsdl.types.lb.QueryRecord;
+import org.glite.wsdl.types.lb.StatName;
+
+/**
+ * This is an example on how to use the package org.glite.lb.notif_java
+ *
+ *
+ * @author Kopac
+ */
+public class NotificationExample {
+
+ /**
+ * example method on how to use this package
+ *
+ * @param args parameters for the methods, order as follows:
+ * <p>
+ * 1. path to user's certificate
+ * <p>
+ * 2. path to a list of trusted certificates
+ * <p>
+ * 3. owner ID
+ * <p>
+ * 4. port number
+ * <p>
+ * 5. LB server address
+ */
+ public static void main(String[] args){
+ try {
+
+ //creation of an instance of class that prepares SSL connection for
+ //webservice, first of the two possibilities is used
+ LBCredentials credentials = new LBCredentials(args[0], args[1]);
+
+ //creation of QueryConditions instance. this one tells the notification to
+ //be associated with jobs of an owner and that don't have a tag. meh
+ QueryRecValue value1 = new QueryRecValue(null, args[2], null);
+ QueryRecord[] record = new QueryRecord[]{new QueryRecord(QueryOp.EQUAL, value1, null)};
+ QueryConditions[] conditions = new QueryConditions[]{new
+ QueryConditions(QueryAttr.OWNER, null, StatName.SUBMITTED, record)};
+
+ //creating an instance of NotificationImpl, the argument is port number
+ Notification notif = new Notification(Integer.parseInt(args[3]), credentials);
+
+ Date date = new Date(System.currentTimeMillis()+86400000);
+
+ //registering a new notification, first parameter is LB server address in String,
+ //second previously created QueryConditions, there are no JobFlags provided
+ //and the last one tells the server to keep it active for two days
+ notif.newNotif(args[4], conditions, null, date);
+
+ //id of the newly created notification
+ String notifId = notif.getNotifid();
+
+ //refreshing the previously created notification by two days
+ notif.refresh(notifId, date);
+
+ //tells the client to read incomming notifications with a timeout of 1 minute
+ JobStatus state = notif.receive(60000);
+ //from here on, state can be used to pick the desired info using its
+ //get methods
+
+ //like this
+ System.out.println(state.getAcl());
+ System.out.println(state.getCancelReason());
+ System.out.println(state.getJobId());
+
+ //creates a new instance of NotificationImpl with the port 14342 and
+ //binds the notification to this new instance, meaning to a new local
+ //address
+ Notification notif2 = new Notification(14342, credentials);
+ notif2.bind(notifId, date);
+
+ //lastly, the notification is dropped
+ notif2.drop(notifId);
+
+ } catch (LBException ex) {
+ Logger.getLogger(NotificationExample.class.getName()).log(Level.SEVERE, null, ex);
+ }
+ }
+}
--- /dev/null
+
+package org.glite.lb;
+
+import holders.StringArrayHolder;
+import java.rmi.RemoteException;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.axis.client.Stub;
+import org.apache.log4j.PropertyConfigurator;
+import org.glite.jobid.Jobid;
+import org.glite.lb.Event;
+import org.glite.lb.Level;
+import org.glite.wsdl.services.lb.LoggingAndBookkeepingPortType;
+import org.glite.wsdl.types.lb.JobFlagsValue;
+import org.glite.wsdl.types.lb.JobStatus;
+import org.glite.wsdl.types.lb.QueryConditions;
+import org.glite.wsdl.types.lb.holders.JobStatusArrayHolder;
+
+/**
+ * This class serves for obtaining data from the bookkeeping
+ * server.
+ * The L&B service queries come in two flavors:
+ * <ol><li type="disc"> conjunctive query, as in <tt>(cond1) or (cond2)</tt></li>
+ * <li type="disc"> conjunction of disjunctive queries, as in <tt>( (cond1)
+ * or (cond2) ) and ( (cond3) or (cond4) )</tt></li></ol>
+ * Methods for both query flavors are provided.
+ * Query methods actually do communicate with the server and
+ * they are synchronous; their completion can take some time
+ * not exceeding the query timeout.
+ *
+ * @author Tomas Kramec, 207545@mail.muni.cz
+ */
+public class ServerConnection {
+
+ private String queryServerAddress;
+ private int queryJobsLimit=0;
+ private int queryEventsLimit=0;
+ private QueryResultsFlag queryResultsFlag = QueryResultsFlag.NONE;
+ private Level eventLogLevel = Level.LEVEL_SYSTEM;
+ private LoggingAndBookkeepingPortType queryServer;
+ private LBCredentials lbCredent;
+
+
+ /**
+ * This enum represents flag to indicate handling of too large results.
+ * In case the result limit is reached:
+ * <ol>
+ * <li><b>NONE</b> - means no results are returned at all.</li>
+ * <li><b>LIMITED</b> - means a result contains at most <i>limit</i> items.</li>
+ * <li><b>ALL</b> - means all results are returned withouth any limitation.</li>
+ * </ol>
+ */
+ public enum QueryResultsFlag {
+ /**
+ * No results are returned at all.
+ */
+ NONE,
+ /**
+ * Result contains at most <i>limit</i> items. Limits for job and event
+ * results can be set by calling appropriate method on the ServerConnection
+ * instance.
+ */
+ LIMITED,
+ /**
+ * Results are returned withouth any limitation.
+ */
+ ALL
+ }
+
+ /**
+ * Constructor initializes the context and
+ * directs new instance to query the given bookkeping server.
+ *
+ * @param server String containing the server address (e.g. https://harad.ics.muni.cz:9453).
+ * @param lbCredent instance of class that holds credentials for SSL authentication
+ */
+ public ServerConnection(String server, LBCredentials lbCredent) throws LBException {
+ if (server == null) throw new IllegalArgumentException("Server cannot be null");
+ if (lbCredent == null) throw new IllegalArgumentException("Credentials cannot be null");
+
+ PropertyConfigurator.configure("log4j.properties");
+ this.lbCredent = lbCredent;
+ setQueryServerAddress(server);
+ setQueryTimeout(120);
+ }
+
+ /**
+ * Set bookkeeping server.
+ * Directs the instance to query the given bookkeping server.
+ *
+ * @param server String containing the server address (e.g. https://harad.ics.muni.cz:9553).
+ */
+ public void setQueryServerAddress(String server) throws LBException {
+ if (server == null) throw new IllegalArgumentException("Server cannot be null");
+
+ queryServer = lbCredent.getStub(server);
+ queryServerAddress = server;
+
+ }
+
+ /**
+ * Get address of the bookkeeping server.
+ * Returns address of the bookkeeping server this instance is
+ * bound to.
+ *
+ * @return Address (https://hostname:port).
+ */
+ public String getQueryServerAddress() {
+ return queryServerAddress;
+ }
+
+ /**
+ * Set query timeout.
+ * Sets the time interval to wait for server response.
+ * Default value is 120 seconds.
+ *
+ * @param time Time in seconds before the query expires. 0 means no timeout.
+ */
+ public void setQueryTimeout(int time) {
+ if (time < 0 || time > 1800)
+ throw new IllegalArgumentException("timeout must be between 0 and 1800");
+
+ ((Stub) queryServer).setTimeout(time*1000);
+
+ }
+
+ /**
+ * Get query timeout.
+ * Returns the time interval this instance waits for server
+ * response.
+ *
+ * @return Number of seconds to wait. 0 means no timeout.
+ */
+ public int getQueryTimeout() {
+ return ((Stub) queryServer).getTimeout()/1000;
+ }
+
+ /**
+ * Set logging level.
+ * Sets the level for logging the events.
+ * Possible values:<ol>
+ * <li type="disc">EMERGENCY</li>
+ * <li type="disc">ALERT</li>
+ * <li type="disc">ERROR</li>
+ * <li type="disc">WARNING</li>
+ * <li type="disc">AUTH</li>
+ * <li type="disc">SECURITY</li>
+ * <li type="disc">USAGE</li>
+ * <li type="disc">SYSTEM</li>
+ * <li type="disc">IMPORTANT</li>
+ * <li type="disc">DEBUG </li>
+ * </ol>
+ * Default value is SYSTEM.
+ * @param loggingLevel level for logging the events
+ */
+ public void setEventLoggingLevel(Level loggingLevel) {
+ if (loggingLevel == null) throw new IllegalArgumentException("loggingLevel");
+
+ this.eventLogLevel = loggingLevel;
+ }
+
+ /**
+ * Get logging level.
+ * Returns the level for logging the events.
+ *
+ * @return level value
+ */
+ public Level getEventLoggingLevel() {
+ return eventLogLevel;
+ }
+
+ /**
+ * Retrieve the set of single indexed attributes.
+ * Returns the set of attributes that are indexed on the
+ * server. Every query must contain at least one indexed
+ * attribute for performance reason; exception to this rule
+ * requires setting appropriate paramater on the server and is
+ * not advised.
+ *<br/>
+ * In the list returned, each element represents a query condition.
+ * Query attribute of the condition corresponds to the indexed attribute.
+ * If the query attribute is USERTAG, tagName is its name;
+ * if it is TIME, statName is state name.
+ *
+ * @return list of QueryConditions
+ * @throws LBException If some communication or server problem occurs.
+ */
+ public List<QueryConditions> getIndexedAttrs() throws LBException {
+ try {
+ QueryConditions[] cond = queryServer.getIndexedAttrs("");
+ List<QueryConditions> indexedAttrs = new ArrayList<QueryConditions>();
+ for (int i = 0; i < cond.length; i++) {
+ indexedAttrs.add(cond[i]);
+ }
+ return indexedAttrs;
+ } catch (RemoteException ex) {
+ throw new LBException(ex);
+ }
+ }
+
+ /**
+ * Retrieve hard result set size limit. This
+ * property is set at the server side.
+ *
+ * Returns the hard limit on the number of
+ * results returned by the bookkeeping server.
+ *
+ * @return Server limit.
+ * @throws LBException If some communication or server problem occurs.
+ */
+ public int getServerLimit() throws LBException {
+ try {
+ return queryServer.getServerLimit("");
+ } catch (RemoteException ex) {
+ throw new LBException(ex);
+ }
+ }
+
+ /**
+ * Set the soft result set size limit.
+ * Sets the maximum number of results this instance is willing
+ * to obtain when querying for jobs.
+ * Default value is 0. It means no limits for results.
+ *
+ * @param jobsLimit Maximum number of results. 0 for no limit.
+ */
+ public void setQueryJobsLimit(int jobsLimit) {
+ if (jobsLimit < 0) throw new IllegalArgumentException("jobsLimit");
+ this.queryJobsLimit = jobsLimit;
+ }
+
+ /**
+ * Get soft result set size limit.
+ * Gets the maximum number of results this instance is willing
+ * to obtain when querying for jobs.
+ *
+ * @return queryJobsLimit Maximum number of results.
+ */
+ public int getQueryJobsLimit() {
+ return queryJobsLimit;
+ }
+
+ /**
+ * Set the soft result set size limit.
+ * Sets the maximum number of results this instance is willing
+ * to obtain when querying for events.
+ * Default value is 0. It means no limits for results.
+ *
+ * @param eventsLimit Maximum number of results. 0 for no limit.
+ */
+ public void setQueryEventsLimit(int eventsLimit) {
+ if (eventsLimit < 0) throw new IllegalArgumentException("eventsLimit");
+ this.queryEventsLimit = eventsLimit;
+ }
+
+ /**
+ * Get soft result set size limit.
+ * Gets the maximum number of results this instance is willing
+ * to obtain when querying for events.
+ *
+ * @return queryEventsLimit Soft limit.
+ */
+ public int getQueryEventsLimit() {
+ return queryEventsLimit;
+ }
+
+ /**
+ * Sets the flag indicating the way of handling of too large query results.
+ * Default is NONE.
+ *
+ * @param flag One of NONE, LIMITED or ALL.
+ */
+ public void setQueryResultsFlag(QueryResultsFlag flag) {
+ if (flag == null) throw new IllegalArgumentException("flag");
+
+ queryResultsFlag = flag;
+ }
+
+ /**
+ * Gest the flag indicating the way of handling of too large query results.
+ *
+ * @return queryResultsFlag
+ */
+ public QueryResultsFlag getQueryResultsFlag() {
+ return queryResultsFlag;
+ }
+
+ /**
+ * Retrieve all events satisfying the conjunctive-disjunctive
+ * query records.
+ * Returns all events belonging to the jobs specified by
+ * <tt>jobCond</tt> and satisfying <tt>queryCond</tt>. The
+ * conditions are given in conjunctive-disjunctive form
+ * <tt>((cond1 OR cond2 OR ...) AND ...)</tt>
+ *
+ * @param jobCond List of conditions on jobs.
+ * @param eventCond List of coditions on events.
+ * @return eventList List of Event objects representing L&B events.
+ * @throws LBException If some communication or server problem occurs.
+ */
+ public List<Event> queryEvents(List<QueryConditions> jobCond,
+ List<QueryConditions> eventCond) throws LBException {
+
+ if (jobCond == null) throw new IllegalArgumentException("jobCond cannot be null");
+ if (eventCond == null) throw new IllegalArgumentException("eventCond cannot be null");
+
+ org.glite.wsdl.types.lb.Event[] events = null;
+ try {
+ events = queryServer.queryEvents(jobCond.toArray(new QueryConditions[jobCond.size()]), eventCond.toArray(new QueryConditions[eventCond.size()]));
+ } catch (RemoteException ex) {
+ throw new LBException(ex);
+ }
+
+ List<Event> eventList= new ArrayList<Event>();
+
+ if (events!= null) {
+ int queryResults;
+ //if the events limit is reached
+ if (queryEventsLimit!=0 && events.length > queryEventsLimit) {
+ queryResults = getResultSetSize(queryEventsLimit, events.length);
+ } else queryResults = events.length;
+
+ EventConvertor convertor = new EventConvertor();
+ for (int i=0;i<queryResults;i++) {
+ eventList.add(convertor.convert(events[i]));
+ }
+ }
+
+ return eventList;
+ }
+
+ /**
+ * Retrieve jobs satisfying the query.
+ * Returns all jobs (represented as JobId's) satisfying query given in
+ * conjunctive-disjunctive form.
+ *
+ * @param query Query in conjunctive-disjunctive form.
+ * @return jobList List of job id's.
+ * @throws LBException If some communication or server problem occurs.
+ */
+ public List<Jobid> queryJobs(List<QueryConditions> query) throws LBException {
+ if (query == null) throw new IllegalArgumentException("query cannot be null");
+
+ StringArrayHolder jobHolder = new StringArrayHolder();
+ try {
+ queryServer.queryJobs(query.toArray(new QueryConditions[query.size()]), new JobFlagsValue[]{}, jobHolder, new JobStatusArrayHolder());
+ } catch (RemoteException ex) {
+ throw new LBException(ex);
+ }
+
+ List<Jobid> jobList = new ArrayList<Jobid>();
+
+ if (jobHolder.value!= null) {
+ int queryResults;
+ int jobsCount = jobHolder.value.length;
+ //if the jobs limit is reached
+ if (queryJobsLimit!=0 && jobsCount > queryJobsLimit) {
+ queryResults = getResultSetSize(queryJobsLimit, jobsCount);
+ } else queryResults = jobsCount;
+
+ for (int i=0;i<queryResults;i++) {
+ jobList.add(new Jobid(jobHolder.value[i]));
+ }
+ }
+
+ return jobList;
+ }
+
+ /**
+ * Retrieve status of jobs satisfying the given query.
+ * Returns states (represented by JobStatus) of all jobs
+ * satisfying the query in conjunctive-disjunctive form.
+ *
+ * @param query Condition on jobs.
+ * @param flags Determine which status fields are actually retrieved.
+ * @return states States of jobs satysfying the condition.
+ * @throws LBException If some communication or server problem occurs.
+ */
+ public List<JobStatus> queryJobStates(List<QueryConditions> query,
+ JobFlagsValue[] flags) throws LBException {
+ if (query == null) throw new IllegalArgumentException("query cannot be null");
+
+ JobStatusArrayHolder jobStatusHolder = new JobStatusArrayHolder();
+ try {
+ queryServer.queryJobs(query.toArray(new QueryConditions[query.size()]), flags, new StringArrayHolder(), jobStatusHolder);
+ } catch (RemoteException ex) {
+ throw new LBException(ex);
+ }
+
+ List<JobStatus> jobStates= new ArrayList<JobStatus>();
+
+ if (jobStatusHolder.value!= null) {
+ int queryResults;
+ int jobsCount = jobStatusHolder.value.length;
+ //if the jobs limit is reached
+ if (queryJobsLimit!=0 && jobsCount > queryJobsLimit) {
+ queryResults = getResultSetSize(queryJobsLimit, jobsCount);
+ } else queryResults = jobsCount;
+
+ for (int i=0;i<queryResults;i++) {
+ jobStates.add(jobStatusHolder.value[i]);
+ }
+ }
+
+ return jobStates;
+ }
+
+ /**
+ * Retrieve status of the job with the given jobId.
+ * Returns state (represented by JobStatus) of the job.
+ *
+ * @param jobId jobId of the job.
+ * @param flags Determine which status fields are actually retrieved.
+ * @return state State of the given job.
+ * @throws LBException If some communication or server problem occurs.
+ */
+ public JobStatus jobState(String jobId, JobFlagsValue[] flags) throws LBException {
+ if (jobId == null) throw new IllegalArgumentException("jobId cannot be null");
+ JobStatus state = new JobStatus();
+ try {
+ state = queryServer.jobStatus(jobId, flags);
+ } catch (RemoteException ex) {
+ throw new LBException(ex);
+ }
+
+ return state;
+ }
+
+ /**
+ * Retrieve states of all user's jobs.
+ * Convenience wrapper around queryJobStates, returns status of all
+ * jobs whose owner is the current user (as named in the X509
+ * certificate subject).
+ *
+ * @return jobStates States of jobs owned by this user.
+ * @throws LBException If some communication or server problem occurs.
+ */
+ public List<JobStatus> userJobStates() throws LBException {
+ JobStatusArrayHolder jobStatusHolder = new JobStatusArrayHolder();
+ try {
+ queryServer.userJobs(new StringArrayHolder(), jobStatusHolder);
+ } catch (RemoteException ex) {
+ throw new LBException(ex);
+ }
+
+ List<JobStatus> jobStates= new ArrayList<JobStatus>();
+
+ if (jobStatusHolder.value!= null) {
+ int queryResults;
+ int jobsCount = jobStatusHolder.value.length;
+ //if the jobs limit is reached
+ if (queryJobsLimit!=0 && jobsCount > queryJobsLimit) {
+ queryResults = getResultSetSize(queryJobsLimit, jobsCount);
+ } else queryResults = jobsCount;
+
+ for (int i=0;i<queryResults;i++) {
+ jobStates.add(jobStatusHolder.value[i]);
+ }
+ }
+
+ return jobStates;
+ }
+
+ /**
+ * Find all user's jobs.
+ * Convenience wrapper around queryJobs, returns id's of all
+ * jobs whose owner is the current user (as named in the X509
+ * certificate subject).
+ *
+ * @return jobs List of jobs(IDs) owned by this user.
+ * @throws LBException If some communication or server problem occurs.
+ */
+ public List<Jobid> userJobs() throws LBException {
+ StringArrayHolder jobHolder = new StringArrayHolder();
+ try {
+ queryServer.userJobs(jobHolder, new JobStatusArrayHolder());
+ } catch (RemoteException ex) {
+ throw new LBException(ex);
+ }
+
+ List<Jobid> jobs= new ArrayList<Jobid>();
+
+ if (jobHolder.value!= null) {
+ int queryResults;
+ int jobsCount = jobHolder.value.length;
+ //if the jobs limit is reached
+ if (queryJobsLimit!=0 && jobsCount > queryJobsLimit) {
+ queryResults = getResultSetSize(queryJobsLimit, jobsCount);
+ } else queryResults = jobsCount;
+
+ for (int i=0;i<queryResults;i++) {
+ jobs.add(new Jobid(jobHolder.value[i]));
+ }
+ }
+
+ return jobs;
+ }
+
+ /**
+ * This private method returns result set size number according to
+ * queryResultsFlag, which indicates handling of too large results.
+ *
+ * @param queryLimit The user limit.
+ * @param results Result set size returned by LB server.
+ * @return number of results this instance is going to return
+ */
+ private int getResultSetSize(int queryLimit, int results) {
+ if (queryLimit < 0) throw new IllegalArgumentException("queryLimit");
+ if (results < 0) throw new IllegalArgumentException("results");
+
+ switch (queryResultsFlag) {
+ case ALL: return results;
+ case LIMITED: return queryLimit;
+ case NONE: return 0;
+ default: throw new IllegalArgumentException("wrong QueryResult");
+ }
+ }
+
+}
+
+
--- /dev/null
+package org.glite.lb;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.Iterator;
+import java.util.List;
+import org.glite.jobid.Jobid;
+import org.glite.lb.Event;
+import org.glite.wsdl.types.lb.JobStatus;
+import org.glite.wsdl.types.lb.QueryAttr;
+import org.glite.wsdl.types.lb.QueryConditions;
+import org.glite.wsdl.types.lb.QueryOp;
+import org.glite.wsdl.types.lb.QueryRecValue;
+import org.glite.wsdl.types.lb.QueryRecord;
+import org.glite.wsdl.types.lb.StatName;
+import org.glite.wsdl.types.lb.Timeval;
+
+
+
+/**
+ * This is a demonstration class for query API.
+ * It contains all possible methodes that can be called on ServerConnection
+ * and Job objects.
+ * @author Tomas Kramec, 207545@mail.muni.cz
+ */
+public class ServerConnectionExample {
+
+
+ /**
+ * This method serves for formating output information about given job status.
+ * It is only an example of how the data can be presented. It can be changed
+ * by user's needs.
+ *
+ * @param status Job status
+ * @return text representation of the given status
+ */
+ private static String jobStatusToString(JobStatus status) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("State: "+status.getState()+"\n");
+ sb.append("Job ID: "+status.getJobId()+"\n");
+ sb.append("Owner: "+status.getOwner()+"\n");
+ sb.append("Job type: "+status.getJobtype()+"\n");
+ sb.append("Destination: "+status.getLocation()+"\n");
+ sb.append("Done code: "+status.getDoneCode()+"\n");
+ sb.append("User tags: ");
+ //if there are some user tags write it out.
+ if (status.getUserTags() != null) {
+ for (int i=0;i<status.getUserTags().length;i++) {
+ if (i==0) {
+ sb.append(status.getUserTags()[i].getTag()+" = "+
+ status.getUserTags()[i].getValue()+"\n");
+ } else sb.append(" "+status.getUserTags()[i].getTag()+
+ " = "+ status.getUserTags()[i].getValue()+"\n");
+ }
+ } else sb.append("\n");
+ //Write the time info in a readable form.
+ Calendar calendar = new GregorianCalendar();
+ DateFormat df = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
+ calendar.setTimeInMillis(status.getStateEnterTime().getTvSec()*1000);
+
+ sb.append("Enter time: "+ df.format(calendar.getTime())+"\n");
+ calendar.setTimeInMillis(status.getLastUpdateTime().getTvSec()*1000);
+ sb.append("Last update time: "+df.format(calendar.getTime())+"\n");
+ return sb.toString();
+ }
+
+ /**
+ * @param args the command line arguments
+ */
+ public static void main(String[] args) throws LBException {
+
+ if (args.length != 8) {
+ System.out.println("To use this class you have to run it with these arguments," +
+ "in this order: \n" +
+ "1. path to the trusted CA's files, default is /etc/grid-security/certificates/\n"+
+ "2. -p for proxy based authentication\n" +
+ " -c for certificate based authentication\n"+
+ "3. proxy certificate\n"+
+ "4. user certificate\n"+
+ "5. user key\n"+
+ "6. user password\n"+
+ "7. LB server addres in format \"https://somehost:port\"\n"+
+ "8. jobid for queries in format \"https://somehost:port/uniquePart\"\n"+
+ "Enter \"\" for empty option.");
+
+ } else {
+
+ /**
+ * create new instance of LBCredentials that holds credentials data
+ * used for authentication
+ */
+ LBCredentials lbCredent = null;
+
+ //if -p option is choosed set the proxy file for authentication
+ //if -c option is choosed set user certificate, key and password
+ if (args[1].equals("-p")) {
+ lbCredent = new LBCredentials(args[2], args[0]);
+ } else if (args[1].equals("-c")) {
+ lbCredent = new LBCredentials(args[3], args[4], args[5], args[0]);
+ } else {
+ System.err.println("Wrong option: "+args[1]+". Only -p and -c is allowed.");
+ System.exit(-1);
+ }
+
+ //create new instance of ServerConnection with the given LB server address
+ ServerConnection sc = new ServerConnection(args[6], lbCredent);
+
+ /**
+ * It is also possible to set these attributes of ServerConnection instance:
+ * timeout for server response
+ * limit for job results
+ * limit for event results
+ * flag indicating the way of handling too large results
+ * loggin level for events
+ * LB server addres
+ */
+// sc.setQueryTimeout(60);
+// sc.setQueryJobsLimit(100);
+// sc.setQueryEventsLimit(50);
+// sc.setQueryResultsFlag(ServerConnection.QueryResultsFlag.LIMITED);
+// sc.setEventLoggingLevel(Level.LEVEL_DEBUG);
+// sc.setQueryServerAddress("https://changedHost", 1234);
+
+ //Get the server limit for query results
+ System.out.println("Limit: " + sc.getServerLimit());
+
+ System.out.println();
+ /**
+ * Print all indexed attributes from LB database.
+ * If the attribute is USERTAG then print its name,
+ * if it is TIME then print state name.
+ */
+ System.out.println("Indexed attributes:");
+ List<QueryConditions> idx = sc.getIndexedAttrs();
+ for (int i=0;i<idx.size();i++) {
+ String name = idx.get(i).getAttr().getValue();
+ System.out.print(idx.get(i).getAttr().getValue());
+ if(name.equals("USERTAG"))
+ System.out.print(" "+ idx.get(0).getTagName());
+ if(name.equals("TIME"))
+ System.out.print(" "+ idx.get(0).getStatName());
+ System.out.println();
+ }
+
+
+ /**
+ * Print all user's jobs and their states.
+ */
+ System.out.println();
+ System.out.println("-----ALL USER's JOBS and STATES----");
+ //get user jobs
+ List<Jobid> jobs = sc.userJobs();
+ //get their states
+ List<JobStatus> js = sc.userJobStates();
+ Iterator<Jobid> it = jobs.iterator();
+ Iterator<JobStatus> itJs = js.iterator();
+ while (it.hasNext()) {
+ System.out.println(it.next());
+ System.out.println(jobStatusToString(itJs.next()));
+ }
+
+ //Demonstration of Job class
+ System.out.println();
+ System.out.println("----------------JOB----------------");
+
+ //create new Job
+ Job myJob = new Job(args[7], sc);
+ //print job state info
+ System.out.println();
+ System.out.println("Status: " + jobStatusToString(myJob.getStatus(null)));
+
+ //print info about job's events
+ System.out.println();
+ List<Event> events = myJob.getEvents();
+ System.out.println("Found "+events.size()+" events:");
+ for (int i=0;i<events.size();i++) {
+ System.out.println("Event: " + events.get(i).info());
+ }
+
+ /**
+ * This is demonstration of creating and using query conditions.
+ * It prints information about all user's jobs registered in LB
+ * submitted in last 3 days.
+ */
+ if (!jobs.isEmpty()) {
+ System.out.println();
+ System.out.println("-------------CONDITIONS------------");
+
+ //create query record for job ids from the previous query on all user's jobs.
+ List<QueryRecord> recList = new ArrayList<QueryRecord>();
+ int port = Integer.parseInt((args[6].split(":"))[2]);
+ for (int i=0;i<jobs.size();i++) {
+ if(jobs.get(i).getPort() == port) {
+ QueryRecValue jobIdValue = new QueryRecValue(null, jobs.get(i).toString(), null);
+ recList.add(new QueryRecord(QueryOp.EQUAL, jobIdValue, null));
+ System.out.println(jobIdValue.getC());
+ }
+ }
+ QueryRecord[] jobIdRec = new QueryRecord[]{};
+ jobIdRec = recList.toArray(jobIdRec);
+
+ //crete QueryConditions instance this formula:
+ //(JOBID='jobId1' or JOBID='jobId2 or ...) where jobId1,... are ids of user's jobs
+ QueryConditions condOnJobid = new QueryConditions(QueryAttr.JOBID, null, null, jobIdRec);
+
+ //create query record for time
+ long time = System.currentTimeMillis()/1000;
+ QueryRecValue timeFrom = new QueryRecValue(null, null, new Timeval(time-259200, 0));
+ QueryRecValue timeTo = new QueryRecValue(null, null, new Timeval(System.currentTimeMillis()/1000, 0));
+ QueryRecord[] timeRec = new QueryRecord[]{new QueryRecord(QueryOp.WITHIN, timeFrom, timeTo)};
+ //create QueryConditions instance representing this formula:
+ //(TIME is in <timeFrom, timeTo> interval)
+ QueryConditions condOnTime = new QueryConditions(QueryAttr.TIME, null, StatName.SUBMITTED, timeRec);
+
+ //create QueryConditions list representing this formula:
+ //(JOBID='jobId1' or JOBID='jobId2 or ...) AND (TIME is in <timeFrom, timeTo> interval)
+ //where jobId1,... are ids of user's jobs
+ List<QueryConditions> condList = new ArrayList<QueryConditions>();
+ condList.add(condOnJobid);
+ condList.add(condOnTime);
+
+ //get all jobs matching the given conditions
+ List<Jobid> jobResult = sc.queryJobs(condList);
+ //get all their states
+ List<JobStatus> jobStatesResult = sc.queryJobStates(condList, null);
+
+ //Print information about results
+ Calendar calendar = new GregorianCalendar();
+ DateFormat df = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
+ System.out.println();
+ System.out.print("Jobs registered ");
+ calendar.setTimeInMillis(timeFrom.getT().getTvSec()*1000);
+ System.out.print("from "+ df.format(calendar.getTime())+" ");
+ calendar.setTimeInMillis(timeTo.getT().getTvSec()*1000);
+ System.out.print("to "+ df.format(calendar.getTime())+"\n");
+ Iterator<Jobid> jobsit = jobResult.iterator();
+ Iterator<JobStatus> statusit = jobStatesResult.iterator();
+ while (jobsit.hasNext()) {
+ System.out.println(jobsit.next());
+ System.out.println(jobStatusToString(statusit.next()));
+ }
+ }
+
+ }
+ }
+}