Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
net.segoia.util.parser.ParseHandler Maven / Gradle / Ivy
/**
* commons - Various Java Utils
* Copyright (C) 2009 Adrian Cristian Ionescu - https://github.com/acionescu
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.segoia.util.parser;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.List;
import net.segoia.commons.exceptions.ContextAwareException;
import net.segoia.util.parser.event.AssociationEvent;
import net.segoia.util.parser.event.GroupEvent;
import net.segoia.util.parser.event.ParseEventHandler;
public class ParseHandler {
private ParseEventHandler eventHandler;
private Deque waitingStack = new ArrayDeque();
private Deque availableStack = new ArrayDeque();
private boolean atomicGroupStarted = false;
private String pendingContent;
private Symbol previousSymbol;
private Deque startedGroups = new ArrayDeque();
private Deque activeContexts = new ArrayDeque();
// private Deque>> currentGroupTypes = new ArrayDeque>>();
public ParseHandler() {
}
public ParseHandler(ParseEventHandler peh) {
this.eventHandler = peh;
}
public void onNewSymbolFound(Symbol symbol, int startIndex, String content) throws ContextAwareException {
// System.out.println("found " + symbol.getSequence() + " at " + startIndex + " : " + content);
SymbolType symbolType = symbol.getType();
if (atomicGroupStarted) { /* we have an atomic group already started */
if (!symbol.equals(previousSymbol)) { /*
* this is not the expected atomic group separator, it will not be
* processed
*/
/* append to pending content. append also the symbol sequence */
appendToPendingContent(content + symbol.getSequence());
return;
} else {
/* if this is the expected symbol, append only the content */
appendToPendingContent(content);
}
}
switch (symbolType) {
case GROUP_START:
handleStartGroup(symbol, startIndex, content);
break;
case GROUP_END:
handleEndGroup(symbol, startIndex, content);
break;
case ASSOCIATE:
handleAssociate(symbol, startIndex, content);
break;
case SEPARATE:
handleSeparate(symbol, startIndex, content);
break;
case GROUP_END_START:
handleEndGroup(symbol, startIndex, content);
handleStartGroup(symbol, startIndex, content);
break;
// case UNIQUE_GROUP_SEPARATOR:
// handleUniqueGroupSeparator(symbol, startIndex, content);
// break;
}
previousSymbol = symbol;
// System.out.println("waiting = " + waitingStack);
// System.out.println("available = " + availableStack);
}
private void appendToPendingContent(String content) {
if (pendingContent == null) {
pendingContent = "";
}
pendingContent += content;
}
private String digestPendingContent() {
String s = pendingContent;
pendingContent = null;
return s;
}
public void handleStartedGroups(Symbol currentSymbol) {
SymbolType ctype = currentSymbol.getType();
if (ctype.equals(SymbolType.GROUP_START)) {
startedGroups.push(currentSymbol);
// System.out.println("group started for "+currentSymbol);
} else if (ctype.equals(SymbolType.GROUP_END) && !startedGroups.isEmpty()) {
startedGroups.pop();
// System.out.println("group closed for "+currentSymbol);
}
}
/**
* Checks if the last started group contains the specified flag
*
* @param flag
* @return
*/
private boolean checkGroupFlag(String flag) {
if (hasStartedGroups()) {
return startedGroups.peek().containsFlag(flag);
}
return false;
}
private boolean checkActiveContextFlag(String flag) {
if(activeContexts.size() > 0) {
return activeContexts.peek().containsFlag(flag);
}
return false;
}
public boolean checkPotentialNestedSymbolMatch(String s) {
if (!startedGroups.isEmpty()) {
return startedGroups.peek().checkPotentialNestedSymbolMatch(s);
}
return false;
}
public boolean hasStartedGroups() {
return !startedGroups.isEmpty();
}
public ParseContextConfig getActiveContext(ParseContextConfig currentContext) {
if (activeContexts.size() > 0) {
return activeContexts.peek();
}
return currentContext;
}
public SymbolSet getActiveSymbolSet() {
if (hasStartedGroups()) {
return startedGroups.peek().getNestedSymbols();
}
return null;
}
public List getNestedSymbol(String seq) {
if (!startedGroups.isEmpty()) {
return startedGroups.peek().getNestedSymbol(seq);
}
return new ArrayList();
}
public void onStartOfFile(ParseContextConfig context) {
activeContexts.push(context);
}
public void onEndOfFile(String content) throws ParserException, ContextAwareException {
while (waitingStack.size() > 0) {
List pairSymbols = waitingStack.pop().getSymbol().getPairSymbols();
/* if at least one pair symbol is multiple don't mention the error */
boolean allowed = false;
for (Symbol ps : pairSymbols) {
if (ps.containsFlag(SymbolFlag.MULTIPLE)) {
allowed = true;
break;
}
}
if (!allowed) {
throw new ParserException("Expected: " + pairSymbols + "\nwaitingStack: " + waitingStack
+ "\navailableStack: " + availableStack);
}
}
ParseContextConfig activeContext = getActiveContext(null);
boolean add = false;
if (activeContext != null) {
String trimmedContent = content.trim();
boolean ignoreEmpty = activeContext.containsFlag(SymbolFlag.IGNORE_EMPTY);
add = !ignoreEmpty || !"".equals(trimmedContent);
if (add && ignoreEmpty) {
content = trimmedContent;
}
} else {
add = (previousSymbol != null && (previousSymbol.getType().equals(SymbolType.SEPARATE) || previousSymbol
.getType().equals(SymbolType.ASSOCIATE)));
}
;
if (add) {
Object handledContent = eventHandler.handleEmptyString(content);
makeAvailable(handledContent);
}
}
private void handleStartGroup(Symbol symbol, int startIndex, String content) throws ContextAwareException {
// System.out.println(symbol+" at:"+startIndex+" content:"+content);
if (symbol.containsFlag(SymbolFlag.SEPARATE)) {
handleSeparate(symbol, startIndex, content);
}
WaitInfo wi = new WaitInfo(symbol, content, availableStack.size());
wi.setFoundIndex(startIndex);
waitingStack.push(wi);
startedGroups.push(symbol);
if (symbol.isOverrideSuperContextConfig()) {
activeContexts.push(symbol);
}
// if(symbol.containsFlag(SymbolFlag.FOLLOW_TYPES)) {
// currentGroupTypes.push(new HashSet>());
// }
}
private void handleEndGroup(Symbol symbol, int startIndex, String content) throws ContextAwareException {
// System.out.println(symbol+" at:"+startIndex+" content:"+content);
/* if the stack is empty it means the text is not formatted return or throw an error */
if (waitingStack.size() > 0) {
// boolean isIgnored = SymbolFlags.IGNORE.equals(waitingStack.peek().getSymbol().getAction());
boolean isIgnored = waitingStack.peek().getSymbol().containsFlag(SymbolFlag.IGNORE);
if (!isIgnored) {
/* end group also plays a separator role */
handleSeparate(symbol, startIndex, content);
}
/*
* and now the next object in the waiting stack should be the one created when the group started, so let's
* try to make an object from it.
*/
WaitInfo wi = waitingStack.pop();
Symbol startGroupSymbol = wi.getSymbol();
/* if this group is ignored, drop the content */
if (!isIgnored) {
/* get the objects from the group */
List objects = getAvailableObjectFromIndex(wi.getAvailableStackIndex());
GroupEvent ge = new GroupEvent();
ge.setEndSymbol(symbol);
ge.setStartSymbol(startGroupSymbol);
ge.setStartIndex(wi.getFoundIndex());
ge.setObjects(objects);
ge.setPrefixValue(wi.getPreviousValue());
/* delegate to the event handler to create an object, push it to the stack */
Object resObj = eventHandler.handleGroupEvent(ge);
/* call workers if any */
if (startGroupSymbol.hasWorkers()) {
resObj = startGroupSymbol.applyWorkers((Collection) resObj);
}
if (symbol.containsFlag(SymbolFlag.UNGROUP)) {
for (Object o : (Collection) resObj) {
makeAvailable(o);
}
} else {
makeAvailable(resObj);
}
// if(startGroupSymbol.containsFlag(SymbolFlag.FOLLOW_TYPES)) {
// currentGroupTypes.pop();
// }
}
if (!startedGroups.isEmpty()) {
startedGroups.pop();
}
if (startGroupSymbol.isOverrideSuperContextConfig()) {
activeContexts.pop();
}
}
}
private void handleAssociate(Symbol symbol, int startIndex, String content) throws ContextAwareException {
Object prevValue = getPreviousValue(content);
WaitInfo prevWaiting = waitingStack.peek();
if (prevWaiting != null) {
Symbol prevSymbol = prevWaiting.getSymbol();
/* if the previous waiting symbol has higher priority than this one, should be handled first */
if (prevSymbol.getType().equals(SymbolType.ASSOCIATE) && prevSymbol.getPriority() <= symbol.getPriority()) {
/* handle the previous waiting object with higher priority */
// handleWaitingObject(prevValue);
makeAvailable(prevValue);
prevValue = getNextAvailableObject();
}
}
WaitInfo wi = new WaitInfo(symbol, prevValue, availableStack.size());
wi.setFoundIndex(startIndex);
waitingStack.push(wi);
}
private void handleSeparate(Symbol symbol, int startIndex, String content) throws ContextAwareException {
SymbolType prevSymbolType = null;
boolean isSeparate = false;
boolean isAssociation = false;
if (previousSymbol != null) {
prevSymbolType = previousSymbol.getType();
isSeparate = prevSymbolType.equals(SymbolType.SEPARATE);
isAssociation = prevSymbolType.equals(SymbolType.ASSOCIATE);
}
boolean isEmptyAndIgnorable = content.trim().isEmpty() && checkActiveContextFlag(SymbolFlag.IGNORE_EMPTY);//checkGroupFlag(SymbolFlag.IGNORE_EMPTY);
if (prevSymbolType != null && (isSeparate || isAssociation)) {
// /* if the last stared group ignores empty elements and this is string is empty do nothig */
if (isAssociation || !isEmptyAndIgnorable) {
Object handledContent = eventHandler.handleEmptyString(content);
makeAvailable(handledContent);
}
} else if (isEmptyAndIgnorable) {
return;
} else {
makeAvailable(getPreviousValue(content));
}
}
private void handleUniqueGroupSeparator(Symbol symbol, int startIndex, String content) throws ContextAwareException {
if (waitingStack.size() == 0) {
atomicGroupStarted = true;
handleStartGroup(symbol, startIndex, content);
return;
}
WaitInfo wi = waitingStack.peek();
if (wi.getSymbol().equals(symbol)) {
/* we have an unpaired symbol of this type so this one must be closing the group */
atomicGroupStarted = false;
/* we will use all the content received until the group was started */
handleEndGroup(symbol, startIndex, digestPendingContent());
} else {
atomicGroupStarted = true;
handleStartGroup(symbol, startIndex, content);
}
}
/**
* Returns the previous value for the current symbol If the parsed content is not empty or null this one is returned
* otherwise the last object made available on the stack is returned
*
* @param content
* @return
* @throws ContextAwareException
*/
private Object getPreviousValue(String content) throws ContextAwareException {
if (content != null && !"".equals(content)) {
return eventHandler.handleEmptyString(content);
} else if (availableStack.size() > 0) {
return getNextAvailableObject();
}
return null;
}
private void handleWaitingObject() throws ContextAwareException {
if (waitingStack.size() <= 0) {
return;
}
WaitInfo wi = waitingStack.peek();
/* this method only handles ASSOCIATIVE symbols */
if (!wi.getSymbol().getType().equals(SymbolType.ASSOCIATE)) {
return;
}
wi = waitingStack.pop();
Object input = getNextAvailableObject();
AssociationEvent ae = new AssociationEvent();
ae.setSymbol(wi.getSymbol());
ae.setStartIndex(wi.getFoundIndex());
ae.setPrefixValue(wi.getPreviousValue());
ae.setPostfixValue(input);
makeAvailable(eventHandler.handleAssociationEvent(ae));
}
private void makeAvailable(Object input) throws ContextAwareException {
if (input != null) {
availableStack.push(input);
} else {
availableStack.push(new NullObject());
}
handleWaitingObject();
// /* follow types */
// if(!currentGroupTypes.isEmpty()) {
// Set> types = currentGroupTypes.peek();
// if(!availableStack.isEmpty()) {
// Object obj = availableStack.peek();
// if(!(obj instanceof NullObject)) {
// types.add(obj.getClass());
// }
// }
// }
}
private List getAvailableObjectFromIndex(int index) {
List data = new ArrayList();
while (availableStack.size() > index) {
data.add(getNextAvailableObject());
}
Collections.reverse(data);
return data;
}
private Object getNextAvailableObject() {
Object o = availableStack.pop();
if (o instanceof NullObject) {
return null;
}
return o;
}
/**
* @return the eventHandler
*/
public ParseEventHandler getEventHandler() {
return eventHandler;
}
/**
* @param eventHandler
* the eventHandler to set
*/
public void setEventHandler(ParseEventHandler eventHandler) {
this.eventHandler = eventHandler;
}
public Deque getObjectsStack() {
return availableStack;
}
class NullObject {
}
}