/* * Copyright (C) 2008 Universidade Federal de Campina Grande * * This file is part of OurGrid. * * OurGrid 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 3 of the License, or (at your option) * any later version. * * This program 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 program. If not, see <http://www.gnu.org/licenses/>. * */ package org.ourgrid.common.specification.worker; import java.util.Iterator; import java.util.Map; import java.util.TreeMap; import java.util.Map.Entry; import org.ourgrid.common.specification.OurGridSpecification; import org.ourgrid.common.specification.main.ClassAdSyntacticalAnalyzerStream; import org.ourgrid.common.specification.main.SDFClassAdsSyntacticalAnalyzer; import org.ourgrid.common.util.CommonUtils; import org.ourgrid.worker.WorkerConstants; import condor.classad.AttrName; import condor.classad.AttrRef; import condor.classad.ClassAdParser; import condor.classad.Constant; import condor.classad.Expr; import condor.classad.ListExpr; import condor.classad.RecordExpr; /** * Entity that encapsulates all the information given by the user about a Worker * To provide the information, the user uses the Description Files that can be * compiled by CommonCompiler. */ public class WorkerSpecification extends OurGridSpecification { private static final long serialVersionUID = 40L; private transient RecordExpr record;//RecordExpr containing worker attributes /** * Pairs of attribute=value provided by the users. */ protected Map<String, String> annotations; /** * Default empty constructor */ public WorkerSpecification() { this( new TreeMap<String, String>()); } /** * Constructor using attributes from a map. Used with SDF. * @param attributes A map of attributes */ public WorkerSpecification( Map<String,String> attributes ) { this(attributes, new TreeMap<String, String>()); } /** * Constructor using attributes and annotations from maps. Used with SDF. * @param attributes A map of attributes */ public WorkerSpecification( Map< String, String > attributes, Map< String, String > annotations ) { super( attributes ); this.annotations = annotations; } /** * Default ClassAd constructor. * @param attributes A {@link RecordExpr} containing the parsed ClassAd. */ public WorkerSpecification( RecordExpr attributes ) { this(attributes, new TreeMap<String, String>()); } /** * Default ClassAd constructor. * @param attributes A {@link RecordExpr} containing the parsed ClassAd. * @param annotations A collection of annotations to do something we still don't know what it is. */ public WorkerSpecification( RecordExpr attributes, Map< String, String > annotations ) { super(); this.annotations = annotations; record = attributes; setExpression( attributes.toString() ); } /** * Constructor receiving a string that represents a classad expression * that describes the worker. * @param expression The classad expression that describes a worker */ public WorkerSpecification( String expression ) { this.annotations = CommonUtils.createSerializableMap(); setExpression( expression ); checkRecordExpression(); generateRecordExprString(); } /** * This method adds an annotation to the current worker * @param property The attribute name * @param value The attribute value */ public void addAnnotation( String property, String value ) { this.annotations.put( property, value ); } /** * Returns the value of an annotation given its attribute name. * * @param attName the attribute name. * @return the attribute value. */ public String getAnnotation( String attName ) { String value = this.annotations.get( attName ); if ( value != null ) { return value; } return null; } /** * Sets the annotations collection. * * @param annotations annotations specified by pairs attribute=value. */ public void setAnnotations( Map<String, String> annotations ) { this.annotations = annotations; } /** * Adds an annotations collection. * * @param annotations annotations specified by pairs attribute=value. */ public void addAllAnnotations( Map<String, String> annotations ) { this.annotations.putAll(annotations); } /** * Retrieves the map of annotations. * * @return a map with all the attributes of this grid machine indexed by the * name of the attribute. */ public Map<String,String> getAnnotations() { return this.annotations; } /** * @see OurGridSpecification#getModuleName */ @Override public String getModuleName() { return WorkerConstants.MODULE_NAME; } /** * @see OurGridSpecification#getObjectName */ @Override public String getObjectName() { return WorkerConstants.LOCAL_WORKER_MANAGEMENT; } @Override public int hashCode(){ final int PRIME = 31; int result = super.hashCode(); result = PRIME * result + ((this.annotations == null) ? 0 : this.annotations.hashCode()); return result; } @Override public String toString(){ StringBuffer s = new StringBuffer(super.toString()); s.append( "Annotations: " + this.annotations.size() ).append( " \t" ); for (Entry<String,String> entry : this.annotations.entrySet()) { //s.append( entry.getKey() ).append( " : " ).append( entry.getValue() ).append( System.getProperty("line.separator") ); s.append( entry.getKey() ).append( " : " ).append( entry.getValue() ).append( "; \t" ); } s.append( System.getProperty("line.separator") ); return s.toString(); } @Override public boolean equals(Object obj){ if(usingClassAd()){ if ( !(obj instanceof WorkerSpecification) ) return false; final WorkerSpecification other = (WorkerSpecification) obj; if(other.usingClassAd()){ return this.equalsAd( other ); } return false; } if( !super.equals(obj)) return false; if ( !(obj instanceof WorkerSpecification) ) return false; final WorkerSpecification other = (WorkerSpecification) obj; return this.annotations.equals( other.annotations ); } /** * This method verifies if two workers have the same record expression * @param other Another worker specification * @return True if the classad expressions are equal, false otherwise */ private boolean equalsAd(WorkerSpecification other){ return this.record.sameAs(other.getRecord()); } /** * This method checks if the current worker is being described by a * classad expression. * @return True if the worker is described by a classad expression, false * otherwise */ public boolean usingClassAd(){ String expression = this.attributes.get( WorkerSpecificationConstants.EXPRESSION ); boolean result = expression != null && !(expression.length() == 0); if(result){ checkRecordExpression(); } return result; } /** * Check if the ClassAd record expression has been rebuilt since serialization. */ private void checkRecordExpression() { String expression = this.attributes.get( WorkerSpecificationConstants.EXPRESSION ); if(record == null){ record = (RecordExpr) new ClassAdParser(expression).parse(); } } /** * @see OurGridSpecification#getAttribute(String) */ @Override public String getAttribute(String attName) { if(usingClassAd()){ Expr value = this.record.lookup(attName); if(value != null){ if(value.type == Expr.STRING){ return value.stringValue(); }else{ return value.toString(); } } return null; } return super.getAttribute(attName); } /** * This method retrieves the classad expression that describes * the worker * @return The classad expression */ public RecordExpr getRecord(){ return this.record; } /** * This method retrieves the classad expression string that describes * the worker * @return The classad expression string */ public String getExpression(){ return this.attributes.get( WorkerSpecificationConstants.EXPRESSION ); } /** * This method changes the classad expression that describes the worker * @param attributes The new classad expression */ public void setRecord( RecordExpr attributes ) { this.record = attributes; this.generateRecordExprString(); } /** * This method inserts a new attribute in the classad expression * that describes the worker. * @param name The attribute name * @param value The attribute value */ private void inserRecordAttribute(String name, String value) { ClassAdSyntacticalAnalyzerStream.changeSystemErrToStream(); RecordExpr expr = (RecordExpr) new ClassAdParser(value).parse(); String errorMessage = ClassAdSyntacticalAnalyzerStream.getErrorMessage(); if(errorMessage.length() > 0){ throw new IllegalArgumentException("Mal formed attribute "+name+" "+errorMessage); } this.record.insertAttribute(name, expr); ClassAdSyntacticalAnalyzerStream.resetSystemErr(); } /** * This method creates a string value for the classad expression * that describes the worker. */ private void generateRecordExprString(){ setExpression( this.record.toString() ); } /** * @see OurGridSpecification#putAttribute(String, String) */ @Override public void putAttribute(String name, String value) { if(usingClassAd()){ if(value.contains(SDFClassAdsSyntacticalAnalyzer.LIST_SYMBOL)){ ListExpr listExpr = new ListExpr(); this.record.insertAttribute(name, listExpr); String[ ] values = value.trim().split( "\\{" )[1].split( "\\}" )[0].split( "," ); for ( String v : values ) { listExpr.add( parseAll( v ) ); } }else if(value.contains(SDFClassAdsSyntacticalAnalyzer.RECORD_SYMBOL)){ inserRecordAttribute(name, value); }else{ Constant constant = parseConstant(value); this.record.insertAttribute(name, constant); } this.generateRecordExprString(); }else{ super.putAttribute(name, value); } } /** * This method verifies if a certain attribute value is a classad constant * @param value The attribute value * @return True if the value is a constant, false otherwise */ private Constant parseConstant( String value ) { Constant primitiveValue = parsePrimitiveValue( value ); return primitiveValue != null? primitiveValue : Constant.getInstance(value); } /** * This method parses an attribute value according to classad syntax * @param value The attribute value * @return An expression {@link Expr} that represents the attribute * value */ private Expr parseAll( String value ) { if(value.trim().startsWith( "\"" )){ return Constant.getInstance(value); } Constant parsePrimitiveValue = parsePrimitiveValue( value ); return parsePrimitiveValue != null? parsePrimitiveValue : new AttrRef(value); } /** * This method verifies a certain attribute value is from a primitive * type * @param value The attribute value * @return A constant {@link Constant} that represents the attribute value */ private Constant parsePrimitiveValue( String value ) { if(value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")){ boolean booleanValue = Boolean.valueOf(value); return Constant.getInstance(booleanValue); } try{ Integer intValue = Integer.valueOf(value); return Constant.getInstance(intValue); }catch(Exception e){ } try{ Long longValue = Long.valueOf(value); return Constant.getInstance(longValue); }catch(Exception e){ } try{ Double d = Double.valueOf(value); return Constant.getInstance(d); }catch(Exception e){ } return null; } /** * @see OurGridSpecification#hasAttribute(String) */ @Override public boolean hasAttribute(String name) { if(usingClassAd()){ return this.record.lookup(name) != null; } return super.hasAttribute(name); } /** * @see OurGridSpecification#removeAttribute(String) */ @Override public void removeAttribute(String key) { if( usingClassAd() ){ if( this.record.removeAttribute(AttrName.fromString(key)) != null ){ this.generateRecordExprString(); } }else{ super.removeAttribute(key); } } /** * This method adds a set of attributes that describes the worker * to the current worker classad expression * @param expr An expression containing new attributes */ @SuppressWarnings("unchecked") public void putAttributes(RecordExpr expr){ checkRecordExpression(); Iterator<AttrName> iterator = expr.attributes(); while (iterator.hasNext()) { AttrName name = iterator.next(); this.record.insertAttribute(name, expr.lookup(name)); } } /** * @param expression the expression to set */ public void setExpression( String expression ) { this.attributes.put( WorkerSpecificationConstants.EXPRESSION, expression ); } public void setAttributes( Map<String, String> att) { this.attributes = att; } }