/*
* (C) Copyright IBM Corp. 2013
*
* LICENSE: Eclipse Public License v1.0
* http://www.eclipse.org/legal/epl-v10.html
*/
package com.ibm.gaiandb.webservices.parser.data;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Set;
import java.util.concurrent.Semaphore;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import com.ibm.gaiandb.webservices.patternmatcher.AttributeMatcher;
import com.ibm.gaiandb.webservices.patternmatcher.TagMatcher;
import com.ibm.gaiandb.webservices.patternmatcher.TagPattern;
import com.ibm.gaiandb.webservices.patternmatcher.ValueMatcher;
import com.ibm.gaiandb.webservices.scanner.Tag;
/**
* The purpose of this class is to provide a tool understanding the name of the
* read tags in order to generate logical table based on the read data.
*
* @author remi - IBM Hursley
*
*/
public class LogicalTableGeneratorHandler extends DefaultHandler {
// ----------------------------------------------------------------------------------
// ----------------------------------------------------------------------- ATTRIBUTES
// =========================================================================== Public
// --------------------------------------------------------------------------- Static
// Use PROPRIETARY notice if class contains a main() method, otherwise use
// COPYRIGHT notice.
public static final String COPYRIGHT_NOTICE = "(c) Copyright IBM Corp. 2013";
// -------------------------------------------------------------------------- Dynamic
// ======================================================================== Protected
// --------------------------------------------------------------------------- Static
// -------------------------------------------------------------------------- Dynamic
// ========================================================================== Private
// --------------------------------------------------------------------------- Static
private static final String IGNORE_CLOSED_TAG = "&&&"; // forbidden char in XML
// -------------------------------------------------------------------------- Dynamic
private ArrayList<TagPattern> scannedElements = new ArrayList<TagPattern>();
/**
* The TagMatchers which are gonna be generated while scanning the stream.
* They will then be used as matchers in the MatcherManager
* {@link generatedMatcher}.
*/
private ArrayList<TagMatcher> matchersValueMatchers = new ArrayList<TagMatcher>();
private ArrayList<String> columnNamesValueMatching = new ArrayList<String>();
private ArrayList<TagMatcher> matchersAttributeMatchers = new ArrayList<TagMatcher>();
private ArrayList<String> columnNamesAttributeMatching = new ArrayList<String>();
private Tag lastStartTag = null;
private String lastClosedTag = IGNORE_CLOSED_TAG;
/** Once the stream has been parsed, the class ignore the other read values. */
private boolean ignore = false;
/** Confirm the generation of the logical table is completed. */
private Semaphore sem = new Semaphore(0);
// ----------------------------------------------------------------------------------
// ---------------------------------------------------------------------------- TOOLS
// ----------------------------------------------------------------------------------
// -------------------------------------------------------------------------- METHODS
// ===================================================================== Constructors
// --------------------------------------------------------------------------- Public
public LogicalTableGeneratorHandler() {
}
// -------------------------------------------------------------------------- Private
// =========================================================================== Public
// --------------------------------------------------------------------------- Static
// -------------------------------------------------------------------------- Dynamic
public ArrayList<TagMatcher> getValueMatchers() {
return matchersValueMatchers;
}
public String[] getColumnNamesValueMatching() {
return columnNamesValueMatching.toArray(new String[0]);
}
public ArrayList<TagMatcher> getAttributeMatchers() {
return matchersAttributeMatchers;
}
public String[] getColumnNamesAttributeMatching() {
return columnNamesAttributeMatching.toArray(new String[0]);
}
public Semaphore getSemaphoreMatchingComplete() {
return sem;
}
@Override
public void startElement(String uri, String localName,String qName,
Attributes attributes) throws SAXException {
// If the logical table definition is still not over
if (!this.ignore) {
if (qName.equalsIgnoreCase(this.lastClosedTag)) {
// The logical table definition is done
// this.objectToReturnName = qName;
this.ignore = true;
this.sem.release();
}
else {
// still need to define logical table
TagPattern currentTag = new TagPattern(qName);
this.scannedElements.add(currentTag);
this.lastClosedTag = IGNORE_CLOSED_TAG;
}
this.lastStartTag = new Tag(qName, attributes);
}
}
@Override
public void endElement(String uri, String localName,
String qName) throws SAXException {
if(!this.ignore) {
if (IGNORE_CLOSED_TAG.equals(this.lastClosedTag)) { // /!\ Check on the object, not on the value
// The last one was a startElement
// => We are at the end of a branch
// --- Saves the tag pattern ---
// - The value pattern
// Column values
this.columnNamesValueMatching.add(qName);
// Adds the value matcher for this end of branch
ArrayList<TagPattern> patterns = new ArrayList<TagPattern>(this.scannedElements);
this.matchersValueMatchers.add(new ValueMatcher(patterns));
// - The Attribute pattern
// For each attribute of the last start element visited
HashMap<String, String> tagsAttributes = this.lastStartTag.getAttributes();
if (tagsAttributes != null) {
Set<String> attributesNamingColumns = tagsAttributes.keySet();
for (String attributeNamingColumn : attributesNamingColumns) {
// Column values
this.columnNamesAttributeMatching.add(attributeNamingColumn);
// Adds the attribute matcher
ArrayList<TagPattern> attributePatterns =
new ArrayList<TagPattern>(this.scannedElements);
this.matchersAttributeMatchers.add(
new AttributeMatcher(attributePatterns,
attributeNamingColumn,
attributePatterns.size() - 1
)
);
}
}
}
this.lastClosedTag = qName;
int nbElements = this.scannedElements.size();
this.scannedElements.remove(nbElements-1); // removes the last element
if (nbElements == 1) {
// We are currently closing the root
// this.objectToReturnName = qName;
this.sem.release();
}
}
}
// ======================================================================== Protected
// --------------------------------------------------------------------------- Static
// -------------------------------------------------------------------------- Dynamic
// ========================================================================== Private
// --------------------------------------------------------------------------- Static
// -------------------------------------------------------------------------- Dynamic
}