www.pudn.com > sxg.rar > ContextGetRequest.java


/*
 * Copyright (c) 2003 Jens Mueller
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2, 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; see the file COPYING.  If not, write to
 * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

/**
	Data class representig get-requests on a single context / SNMP-agent.

 	@author Jens Mueller
 */

import java.net.InetAddress;
import java.net.SocketException;

import java.util.List;
import java.util.StringTokenizer;
import java.util.Vector;
import java.util.Iterator;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.dom4j.xpath.DefaultXPath;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.dom4j.Branch;
import org.dom4j.Namespace;
import org.dom4j.QName;
import org.dom4j.XPath;
import org.dom4j.io.XMLWriter;
import org.dom4j.io.OutputFormat;

public class ContextGetRequest
{

	private String _ipaddr;
	private InetAddress _inetAddress;
	private int _port;
	private String _commString;
	private boolean _caching;
	/**
		the part of the requeststring following the context. For example, for a get-request containing
		the request "/context[@hostname="localhost"](/ifEntry|/tcpConnEntry[tcpConnState="listen"])
		_xPath will contain "(/ifEntry|/tcpConnEntry[tcpConnState="listen"])". 	 */
	private String _xPath;
	private Vector _GwComplexTypeVector;
	private Document _resDocument;
	
	public ContextGetRequest()
	{
		_caching = true;
		_port = GatewayConf.DEFAULT_PORT;
		_commString = GatewayConf.DEFAULT_COMM_STR;
		_GwComplexTypeVector = new Vector();
		_resDocument = DocumentHelper.createDocument();
	}
	
	public void setIPaddr( String addr )
	{
		_ipaddr = addr;
	}

	public void setInetAddress( InetAddress address )
	{
		_inetAddress = address;
	}
	
	public void setPort( int port )
	{
		_port = port;
	}

	public void setCommString( String communityString )
	{
		_commString = communityString;
	}

	public void setCaching( boolean value )
	{
		_caching = value;
	}
	
	public void setXPath( String defXPath )
	{
		_xPath = defXPath;
	}
	
	
	public String getIPaddr()
	{
		return _ipaddr;
	}

	public InetAddress getInetAddress()
	{
		return _inetAddress;
	}

	public int getPort()
	{
		return _port;
	}

	public String getCommString()
	{
		return _commString;
	}
	
	public boolean isCacheRequest()
	{
		return _caching;
	}
	
	public String getXPath()
	{
		return _xPath;
	}
	
	public Document getResultDocument()
	{
		return _resDocument;
	}
	
	
	/**
		parses the private String _xPath and resolves the 
		corresponding GwComplexTypes calling 
		MibRepositoryHandler.getTypes(String name). Results are stored in
		private Vector _GwComplexTypeVector
		
	 	@param repHandler	the MibRepositoryHandler used to create
	 									the GwComplexTypes. 	 */
	private void resolveTypes( MibRepositoryHandler repHandler )
	{
		StringTokenizer strtok = new StringTokenizer( _xPath.toString(), "|");
		String currToken = "";
		while( strtok.hasMoreElements() )
		{
			currToken = strtok.nextToken().trim();
			int i = 0;
			while ( currToken.charAt( i ) == '(' ||
				 	   currToken.charAt( i ) == '/' )
			{
				i++;
			}
			currToken = currToken.substring( i );
			i = currToken.length() - 1;
			boolean charFound = false;
			while ( i >= 0 && !charFound )
			{
				if ( currToken.charAt( i ) != ')' && currToken.charAt( i ) != ' ' )
					charFound = true;
				i--;
			}
			String singleXPath = currToken.substring( 0, i + 2 );
			
			i = 0;
			while ( i < currToken.length() )
			{
				if ( currToken.charAt( i ) == '/' ||
					 currToken.charAt( i ) == '[' ||
					 currToken.charAt( i ) == ')' )
				{
					currToken = currToken.substring( 0, i ).trim();
					break;
				}
				i++;
			}
			
			Vector types = repHandler.getTypes( currToken );
			if ( types != null )
			{
				Iterator iterator = types.iterator();
				while ( iterator.hasNext() )
				{			
					GwComplexType type = ( GwComplexType )iterator.next();
					type.setXPath( singleXPath );
					_GwComplexTypeVector.add( type );					 	
				}
			}
		}
	}


	/**
		adds the XML-representation of a requested SNMP-table to the submitted XML-Element.
		Values of the table-objects are requested using getnext
		
	 	@param currComplexType		the requested table-type 	 	@param snmpHandler			handler used for SNMP-getnext-requests 	 	@param parent						XML-Element to which the content is added 	 	@throws SnmpAccessException 	 */
	private void buildTable(	GwComplexType currComplexType, 
										SnmpHandler snmpHandler, 
										Element parent ) throws SnmpAccessException
	{
		GwElement typeElement;
		EnumElement enumElement;
		// check if  there is something to request
		if (    !( currComplexType._typeElements.isEmpty() 
			 && currComplexType._typeAttributes.isEmpty() ) )
		{
			while ( true )
			{
				// request elements
				for ( Iterator typeIter = currComplexType._typeElements.iterator(); typeIter.hasNext(); )
				{
					typeElement = ( GwElement )typeIter.next();
					typeElement.setExecutionResult( 
											snmpHandler.getNextRequest( typeElement.getOid().toString() ) );
											
					typeElement.setOid( typeElement.getExecutionResult().getOid() );
				}
				// request attributes
				for ( Iterator typeIter = currComplexType._typeAttributes.iterator(); typeIter.hasNext(); )
				{
					typeElement = ( GwElement )typeIter.next();
					typeElement.setExecutionResult( 
											snmpHandler.getNextRequest( typeElement.getOid().toString() ) );
											
					typeElement.setOid( typeElement.getExecutionResult().getOid() );
				}
				
				// last request ran over table, do not persist it and break
				if ( !currComplexType.allTypeOidsPrefixed() )
					break;
						
				// persist tablerow
				else
				{
					Element currTableElement = parent.addElement( currComplexType.getName() );
					
					// adding elements
					for ( Iterator typeIter = currComplexType._typeElements.iterator(); typeIter.hasNext(); )
					{
						typeElement = ( GwElement )typeIter.next();
						String data = typeElement.getEncodedExecutionResult();
						Element currChild = currTableElement.addElement( typeElement.getName() );
						currChild.setText( data );
					}
					// adding attributes
					for ( Iterator typeIter = currComplexType._typeAttributes.iterator(); typeIter.hasNext(); )
					{
						typeElement = ( GwElement )typeIter.next();
						String data = typeElement.getEncodedExecutionResult();
						Element currAttr = currTableElement.addAttribute( typeElement.getName(), data );
					}
				}
			}																	   
		}
	}
	
	
	/**
		adds the XML-representation of a requested SNMP-scalargroup to the submitted 
		XML-Element. Values of the scalar-objects are requested using get.
		
	 	@param currComplexType		the requested scalargroup-type
	 	@param snmpHandler			handler used for SNMP-get-requests
	 	@param context					XML-Element to which the content is added
	 	@throws SnmpAccessException
	 */	
	private void buildSequence( 	GwComplexType currComplexType, 
												SnmpHandler snmpHandler, 
												Element context ) throws SnmpAccessException
	{
		GwElement typeElement;
		EnumElement enumElement;
		Element currComplexTypeElement = context.addElement( currComplexType.getName() );
		for ( Iterator typeIter = currComplexType._typeElements.iterator(); typeIter.hasNext(); )
		{
			typeElement = ( GwElement )typeIter.next();
			try
			{
				typeElement.setExecutionResult( 
										snmpHandler.getRequest( typeElement.getOid().toString()+".0" ) );
			}
			catch( SnmpAccessException e )
			{
				break;
			}
			Element currChild = currComplexTypeElement.addElement( typeElement.getName() );																	   
			String data = typeElement.getEncodedExecutionResult();
			currChild.setText( data );
		}
	}



	/**
	 	adds XML-Elements >snmp-data<>context ... < to
	 	document with proper attributes of the >context ... <
	 	-Element. 	 	@param document		the XML-document the elements are added to 	 	@return Element		the reference to the >context ... <-Element 	 */
	private Element buildDataDocument( Document document )
	{
		Element data = document.addElement( "snmp-data" );
		Element context = data.addElement( GatewayConf.GET_AGENTELEMENT );
		context.addAttribute( GatewayConf.IPADDR, _ipaddr );
		context.addAttribute( GatewayConf.HOSTNAME, _inetAddress.getCanonicalHostName() );
		context.addAttribute( GatewayConf.PORT, Integer.toString( _port ) );
		if ( _caching )
			context.addAttribute( GatewayConf.CACHING, "yes" );
		else
			context.addAttribute( GatewayConf.CACHING, "no" );
		context.addAttribute( GatewayConf.COMM_STR, _commString );
		context.addAttribute( GatewayConf.TIME, GwDate.getCurrent() );
		return context;
	}



	/**
	 	adds an XML-Element >context ... < to
	 	document with proper attributes of the >context ... <
	 	-Element including the time-attribute.
	  	 	@param document		the XML-document the element is added to 	 	@param timeString		value of the time-attribute 	 	@return Element		the reference to the >context ... <-Element 	 */
	private Element buildBaseDocument( Document document, String timeString )
	{
		Element context = document.addElement( GatewayConf.GET_AGENTELEMENT );
		context.addAttribute( GatewayConf.IPADDR, _ipaddr );
		context.addAttribute( GatewayConf.HOSTNAME, _inetAddress.getCanonicalHostName() );

		context.addAttribute( GatewayConf.PORT, Integer.toString( _port ) );
		if ( _caching )
			context.addAttribute( GatewayConf.CACHING, "yes" );
		else
			context.addAttribute( GatewayConf.CACHING, "no" );
		context.addAttribute( GatewayConf.COMM_STR, _commString );
		context.addAttribute( GatewayConf.TIME, timeString );
		return context;
	}




	/**
	 	Executes the represented get-request. Steps are:
	 	1. Obtaining whole tables or scalargroups either from the cache or by calling
	 		methods buildTable or buildSequence.
	 	2. Adding newly requested data to the cache.
	 	3. Executing XPath-expressions requested in requeststring.
	 	4. Building result-document.
	 	 	 	@param repHandler 	 	@return String			debuginformation, not needed to evaluate 	 	@throws RequestExecutionException 	 */
	public String execute( MibRepositoryHandler repHandler ) throws RequestExecutionException
	{
		if( ! _ipaddr.equals( _inetAddress.getHostAddress() ) )
		{
			Element faultyContext = buildDataDocument( _resDocument );
			return( "IP-Adresses do not match" );
		}
		
		resolveTypes( repHandler );
		String debugstr = "";
		
		int[] timeout = new int[ 1 ];
		timeout[ 0 ] = 1000;
		GwComplexType currComplexType;
		SnmpHandler snmpHandler = new SnmpHandler( 	"Agent", 
																				_inetAddress, 
																				_port, 
																				timeout, 
																				_commString );
		boolean resolvedFromCache;
		try
		{
			snmpHandler.connect();
			Element context = buildDataDocument( _resDocument );
			
			//execute each GwComplexType		
			for ( Iterator iterator = _GwComplexTypeVector.iterator(); iterator.hasNext(); ) 
			{
				resolvedFromCache = false;
				currComplexType = ( GwComplexType )iterator.next();
				Element tempContext;
			
				if ( _caching )
				{
					CacheRequestResult result = CacheHandler.getFromCache( currComplexType, this );
					if ( result != null )
					{
						tempContext = buildBaseDocument( 
											currComplexType.getTempDocument(), result.getDate() );
						tempContext.appendContent( result.getResult() );
						resolvedFromCache = true;
					}
				}
				
				if ( !resolvedFromCache )
				{
					tempContext = buildBaseDocument( 
										currComplexType.getTempDocument(), GwDate.getCurrent() );
					// table
					if ( currComplexType.isTable() )
					{
						try 
						{
							buildTable(  currComplexType, snmpHandler, tempContext );
						}
						catch ( SnmpAccessException e )
						{
							throw new RequestExecutionException( "SNMP-Communication failed" );
						}
					}	
					// scalargroup
					else
					{
						try
						{
							buildSequence( currComplexType, snmpHandler, tempContext );
						}
						catch ( SnmpAccessException e )
						{
							throw new RequestExecutionException( "SNMP-Communication failed" );
						}
					}
				}
					
				CacheHandler.cacheIn( currComplexType, this );	
					
				// execution of XPath-Expression	
				XPath path = currComplexType.getTempDocument().createXPath( 
									"/context/"+currComplexType.getXPath() );
				List requestedNodes = path.selectNodes( currComplexType.getTempDocument() );
				
				debugstr += 	"requestedNodes has " + requestedNodes.size() + 
									"elements, executed was XPath-expression: /context/"+
									currComplexType.getXPath()+" 
"; Element currParent = null; Element currComplexTypeElement = null; Element currTypeElement = null; for ( Iterator iter = requestedNodes.iterator(); iter.hasNext(); ) { Object next = iter.next(); //should never happen if ( !( next instanceof Element ) ) { debugstr += "Object found: "+ next.toString() +" not of type Element !
"; throw new RequestExecutionException( "An error occured during processing " + "of request. Check for valid schema-" + "files and try again" ); } else { Element currElement = ( Element )next; Element root = context.getParent().addNamespace( currComplexType.getNamespacePrefix(), currComplexType.getSchemaLocation() ); // ComplexType itself selected if ( currElement.getName().equals( currComplexType.getName() )) { currComplexTypeElement = addElement(currElement, currComplexType.getNamespacePrefix(), currComplexType.getSchemaLocation(), context ); for (Iterator currCmplxIter = currElement.elementIterator(); currCmplxIter.hasNext(); ) { Element currSrcTypeElement = ( Element )currCmplxIter.next(); currTypeElement = addElement(currSrcTypeElement, currComplexType.getNamespacePrefix(), currComplexType.getSchemaLocation(), currComplexTypeElement ); currTypeElement.setText( currSrcTypeElement.getText() ); } } // scalar selected else if ( currElement.getParent().getName().equals( currComplexType.getName() ) ) { if ( currParent == null || !currParent.equals( currElement.getParent() ) ) { //parentNotAppended = false; currComplexTypeElement = addElement( currElement.getParent(), currComplexType.getNamespacePrefix(), currComplexType.getSchemaLocation(), context ); currParent = currComplexTypeElement; } currTypeElement = addElement(currElement, currComplexType.getNamespacePrefix(), currComplexType.getSchemaLocation(), currComplexTypeElement ); currTypeElement.setText( currElement.getText() ); } // there is no second child layer else { throw new RequestExecutionException( "XPath " + currComplexType.getXPath() + "not computable: " + currElement.getParent().getName() + " != "+currComplexType.getName()); } } } } return debugstr; } catch (SocketException e) { throw new RequestExecutionException( "SocketException occured " + "during snmp-connect " + e.getMessage() ); } } /** Adds an XML-Element tp parent @param elem the Element to be added @param namespacePrefix the prefix the added Element should have @param schemaLocation the namespaceURI beloging to namespacePrefix @param parent the element elem should be added to @return Element the reference of the added Element */ private Element addElement( Element elem, String namespacePrefix, String schemaLocation, Element parent ) { Element res = parent.addElement( QName.get( elem.getName(), namespacePrefix, schemaLocation ) ); res.appendAttributes( elem ); return res; } /** writes textual representation of this request to writer for debugging */ public void dump( PrintWriter writer ) { Iterator iterator = _GwComplexTypeVector.iterator(); GwComplexType currCmplxType; GwElement typeElement; EnumElement enumElement; OutputFormat outputformat = new OutputFormat( " ", true ); XMLWriter xmlWriter = new XMLWriter( writer, outputformat ); writer.println(" parsed complex types from xpath: " + _xPath + "
"); while ( iterator.hasNext() ) { currCmplxType = ( GwComplexType )iterator.next(); writer.println( "Name: " + currCmplxType.getName() + "
" ); writer.println( "OID: " +currCmplxType.getOid() + "
" ); writer.println( "Type: " +currCmplxType.getType() + "

" ); writer.println("ELEMENTSCOUNT: "+currCmplxType._typeElements.size() ); for ( Iterator typeIter = currCmplxType._typeElements.iterator(); typeIter.hasNext(); ) { typeElement = (GwElement)typeIter.next(); writer.println( typeElement.dump() ); } writer.println("ATTRIBUTESCOUNT: "+currCmplxType._typeAttributes.size() ); for ( Iterator typeIter = currCmplxType._typeAttributes.iterator(); typeIter.hasNext(); ) { typeElement = (GwElement)typeIter.next(); writer.println( typeElement.dump() ); } try { xmlWriter.write( currCmplxType.getTempDocument() ); } catch ( Throwable th ) { writer.println("Exc during dump-write: "+th.toString()); } } try { xmlWriter.write( _resDocument ); } catch ( Throwable th ) { writer.println("Exc during dump-write: "+th.toString()); } } }