/******************************************************************************* * Copyright (c) 2006-2010 eBay Inc. All Rights Reserved. * 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 *******************************************************************************/ package org.ebayopensource.turmeric.runtime.binding.impl.parser.nv; import javax.xml.stream.XMLStreamException; /** * @author ichernyshev, wdeng */ public final class NVLine { private final NVPathPart[] m_line; private final int m_lineLen; private final String m_value; private final int m_valleyLevel; private final boolean m_isSameLevelAttribute; public NVLine(NVPathPart[] line, int lineLen, String value, int valleyLevel, boolean isSameLevelAttribute) { m_line = line; m_lineLen = lineLen; m_value = value; m_valleyLevel = valleyLevel; m_isSameLevelAttribute = isSameLevelAttribute; } public NVPathPart peek() { return getPathPart(m_lineLen-1); } public String getValue() { return m_value; } public int getDepth() { return m_lineLen; } public NVPathPart getPathPart(int i) { if (i < 0 || i >= m_lineLen) { throw new IllegalArgumentException("Line element index " + i + " is out of range within length of " + m_lineLen); } return m_line[i]; } public int getValleyLevel() { return m_valleyLevel; } public boolean isAttribute() { if (m_lineLen == 0) { return false; } NVPathPart part = peek(); return part.isAttribute(); } public boolean isAttributeAtSameLevel() { return m_isSameLevelAttribute; } public static NVLine createEmpty() { return new NVLine(null, 0, null, -1, false); } public static NVLine createNext(NVStreamParser parser, NVLine aboveLine, NVLine reuse, NVPathPart impliedRoot) throws XMLStreamException { int pathLen = parser.getElementPathLen(); NVStreamParser.NVElementHolder[] holders = parser.getElementPath(); String value = parser.getValue(); // try to reuse or create an array NVPathPart[] line; int minCapacity = pathLen + 1; if (reuse != null && reuse.m_line != null && reuse.m_line.length >= minCapacity) { line = reuse.m_line; } else { line = new NVPathPart[minCapacity + 10]; } int aboveLineDepth = 0; if (aboveLine != null) { aboveLineDepth = aboveLine.getDepth(); } int lineLen = 0; int valleyIndex = -1; // add implied root if necessary if (impliedRoot != null) { line[0] = impliedRoot; valleyIndex = 0; lineLen = 1; } boolean hasDifferenNames = false; for (int i=0; i<pathLen; i++) { NVStreamParser.NVElementHolder holder = holders[i]; if (i == 0 && impliedRoot != null && isSameElementNameAndFlags(holder, impliedRoot)) { String nsUri = parser.getNsUriForElementHolder(holder, true, impliedRoot.getNamespaceURI()); if (nsUri.equals(impliedRoot.getNamespaceURI())) { // we've added implied root already continue; } } // TODO: try to avoid comparing strings if we already had a difference // check whether we have any previous data in the line above if (lineLen >= aboveLineDepth) { line[lineLen++] = parser.buildPathPart(holder, lineLen == 0, null); hasDifferenNames = true; continue; } // check whether name looks similar and we're at the same index NVPathPart abovePathPart = aboveLine.getPathPart(lineLen); if (!isSameElementNameAndFlags(holder, abovePathPart)) { line[lineLen++] = parser.buildPathPart(holder, lineLen == 0, null); hasDifferenNames = true; continue; } // now check that the namespaces match; // by now, we're pretty confident that it's the same name String nsUri = parser.getNsUriForElementHolder(holder, lineLen == 0, null); if (!nsUri.equals(abovePathPart.getNamespaceURI())) { line[lineLen++] = new NVPathPart(nsUri, abovePathPart.getLocalPart(), holder.m_index, holder.m_isAttribute, holder.m_elemNameChecksum); hasDifferenNames = true; continue; } // everything mathces, reuse the path part and update valley if (!hasDifferenNames) { valleyIndex = lineLen; } line[lineLen++] = abovePathPart; } boolean isSameLevelAttribute = line[lineLen-1].isAttribute() && valleyIndex >= lineLen-2; return new NVLine(line, lineLen, value, valleyIndex, isSameLevelAttribute); } private static boolean isSameElementNameAndFlags(NVStreamParser.NVElementHolder holder, NVPathPart otherPathPart) { String otherPathPartLocalName = otherPathPart.getLocalPart(); int elemNameLength = holder.m_elemNameLength; if (otherPathPart.getLocalPartChecksum() != holder.m_elemNameChecksum || otherPathPartLocalName.length() != elemNameLength || otherPathPart.getIndex() != holder.m_index || otherPathPart.isAttribute() != holder.m_isAttribute) { return false; } // check whether name is a actually the same char[] elemNameData = holder.m_elemName; int elemNameStart = holder.m_elemNameStart; for (int i=0; i<elemNameLength; i++) { if (elemNameData[elemNameStart + i] != otherPathPartLocalName.charAt(i)) { return false; } } return true; } }