package nl.ipo.cds.nagios.parser; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import nl.ipo.cds.nagios.ast.ContactStatusNode; import nl.ipo.cds.nagios.ast.HostStatusNode; import nl.ipo.cds.nagios.ast.InfoNode; import nl.ipo.cds.nagios.ast.KVPNode; import nl.ipo.cds.nagios.ast.ObjectNode; import nl.ipo.cds.nagios.ast.ProgramStatusNode; import nl.ipo.cds.nagios.ast.ServiceCommentNode; import nl.ipo.cds.nagios.ast.ServiceStatusNode; public class Parser implements Iterable<ObjectNode> { private ParserContext parserContext; private Lexer lexer; private class ObjectIterator implements Iterator<ObjectNode> { private boolean hasNextObject = false; private ObjectNode nextObject = null; public boolean hasNext() { if (!hasNextObject) { nextObject = object (); hasNextObject = true; } return nextObject != null; } public ObjectNode next() { if (!hasNextObject) { nextObject = object (); } if (nextObject == null) { throw new NoSuchElementException (); } hasNextObject = false; return nextObject; } public void remove() { throw new UnsupportedOperationException (); } } public Parser (final ParserContext parserContext, final Lexer lexer) { this.parserContext = parserContext; this.lexer = lexer; } /** * * @return */ public ObjectNode object () { while (true) { try { if (check (TokenType.EOF)) { return null; } else if (check ("contactstatus")) { return contactStatus (); } else if (check ("hoststatus")) { return hostStatus (); } else if (check ("info")) { return info (); } else if (check ("programstatus")) { return programStatus (); } else if (check ("servicecomment")) { return serviceComment (); } else if (check ("servicestatus")) { return serviceStatus (); } else if (!check (TokenType.NAME)) { error (getLine (), getColumn (), String.format ("Expected object type, found `%s`", getValue ())); } else { error (getLine (), getColumn (), String.format("Unknown object type `%s`", getValue ())); } } catch (ParserException e) { parserContext.reportError (e.getLine (), e.getColumn (), e.getMessage ()); // Skip until the end of the object: try { while (!check (TokenType.EOF) && !check (TokenType.RCURLY)) { accept (); } accept (); } catch (ParserException ex) { // Ignore further parser exceptions until EOF. } // Continue parsing the next object: continue; } break; } return null; } public ContactStatusNode contactStatus () throws ParserException { final int line = getLine (); final int column = getColumn (); expect ("contactstatus"); return new ContactStatusNode ( parserContext, line, column, objectValues () ); } public HostStatusNode hostStatus () throws ParserException { final int line = getLine (); final int column = getColumn (); expect ("hoststatus"); final HostStatusNode status = new HostStatusNode ( parserContext, line, column, objectValues () ); expectValue (status, "host_name"); expectValue (status, "current_state"); expectValue (status, "last_hard_state"); expectValue (status, "plugin_output"); expectValue (status, "plugin_output"); expectValue (status, "long_plugin_output"); expectValue (status, "performance_data"); expectValue (status, "last_check"); expectValue (status, "last_state_change"); expectValue (status, "last_hard_state_change"); expectValue (status, "is_flapping"); expectValue (status, "scheduled_downtime_depth"); return status; } public InfoNode info () throws ParserException { final int line = getLine (); final int column = getColumn (); expect ("info"); return new InfoNode ( parserContext, line, column, objectValues () ); } public ProgramStatusNode programStatus () throws ParserException { final int line = getLine (); final int column = getColumn (); expect ("programstatus"); return new ProgramStatusNode ( parserContext, line, column, objectValues () ); } public ServiceCommentNode serviceComment () throws ParserException { final int line = getLine (); final int column = getColumn (); expect ("servicecomment"); return new ServiceCommentNode ( parserContext, line, column, objectValues () ); } public ServiceStatusNode serviceStatus () throws ParserException { final int line = getLine (); final int column = getColumn (); expect ("servicestatus"); final ServiceStatusNode status = new ServiceStatusNode ( parserContext, line, column, objectValues () ); expectValue (status, "host_name"); expectValue (status, "service_description"); expectValue (status, "current_state"); expectValue (status, "last_hard_state"); expectValue (status, "plugin_output"); expectValue (status, "long_plugin_output"); expectValue (status, "performance_data"); expectValue (status, "is_flapping"); expectValue (status, "scheduled_downtime_depth"); return status; } public List<KVPNode> objectValues () throws ParserException { final List<KVPNode> kvps = new ArrayList<KVPNode> (); expect (TokenType.LCURLY); while (check (TokenType.NAME)) { kvps.add (kvp ()); } expect (TokenType.RCURLY); return kvps; } public KVPNode kvp () throws ParserException { final Token key, value; final int line = getLine (); final int column = getColumn (); key = expect (TokenType.NAME); expect (TokenType.ASSIGN); value = expect (TokenType.VALUE); return new KVPNode (parserContext, line, column, key, value); } private boolean check (final TokenType tokenType) throws ParserException { try { return lexer.la ().getTokenType ().equals (tokenType); } catch (LexerException e) { throw new ParserException (parserContext, e); } } private boolean check (final TokenType tokenType, final String value) throws ParserException { try { return lexer.la ().getTokenType ().equals (tokenType) && lexer.la ().getValue ().equals (value); } catch (LexerException e) { throw new ParserException (parserContext, e); } } private boolean check (final String value) throws ParserException { return check (TokenType.NAME, value); } private Token expect (final TokenType tokenType) throws ParserException { try { if (!check (tokenType)) { error (String.format ("Expected %s, but found `%s`", tokenType, lexer.la ().getValue ())); } return lexer.accept (); } catch (LexerException e) { throw new ParserException (parserContext, e); } } private Token expect (final TokenType tokenType, final String value) throws ParserException { try { if (!check (tokenType, value)) { error (String.format ("Expected `%s`, but found `%s`", value, lexer.la ().getValue ())); } return lexer.accept (); } catch (LexerException e) { throw new ParserException (parserContext, e); } } private Token expect (final String value) throws ParserException { return expect (TokenType.NAME, value); } private void expectValue (final ObjectNode object, final String key) throws ParserException { if (!object.hasValue (key)) { error (object.getLine (), object.getColumn (), String.format ("Object must have a value for `%s`", key)); } } private Token accept () throws ParserException { try { return lexer.accept (); } catch (LexerException e) { throw new ParserException (parserContext, e); } } private void error (final int line, final int column, final String message) throws ParserException { throw new ParserException (parserContext, line, column, message); } private void error (final String message) throws ParserException { try { error (lexer.la ().getLine (), lexer.la ().getColumn (), message); } catch (LexerException e) { throw new ParserException (parserContext, e); } } private int getLine () throws ParserException { try { return lexer.la ().getLine (); } catch (LexerException e) { throw new ParserException (parserContext, e); } } private int getColumn () throws ParserException { try { return lexer.la ().getColumn (); } catch (LexerException e) { throw new ParserException (parserContext, e); } } private String getValue () throws ParserException { try { return lexer.la ().getValue (); } catch (LexerException e) { throw new ParserException (parserContext, e); } } public Iterator<ObjectNode> iterator () { return new ObjectIterator (); } }