/* Copyright (c) 2006 Google Inc.
*
* 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 com.google.api.gbase.client;
import com.google.gdata.util.common.xml.XmlWriter;
import com.google.gdata.data.Extension;
import com.google.gdata.data.ExtensionProfile;
import com.google.gdata.data.AttributeHelper;
import com.google.gdata.data.ExtensionDescription;
import com.google.gdata.util.ParseException;
import com.google.gdata.util.XmlParser;
import org.xml.sax.Attributes;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* Histogram information for one attribute, described in
* an entry using attributes in the gm: namespace.
*
* Make sure the current feed is an histogram feed and then get the
* AttributeHistogram for the entry using:
* {@link GoogleBaseEntry#getGoogleBaseMetadata()}.getAttributeHistogram().
*/
@ExtensionDescription.Default(
nsAlias = GoogleBaseNamespaces.GM_ALIAS,
nsUri = GoogleBaseNamespaces.GM_URI,
localName = "attribute")
public class AttributeHistogram implements Extension {
private GoogleBaseAttributeId attributeId;
private int totalValueCount;
private final List<UniqueValue> values = new ArrayList<UniqueValue>();
/**
* Creates an unitialized AttributeHistogram.
*/
public AttributeHistogram() {
}
/**
* Creates and initializes an AttributeHistogram.
*
* @param attributeName attribute name
* @param attributeType attribute type
*/
public AttributeHistogram(String attributeName,
GoogleBaseAttributeType attributeType) {
attributeId = new GoogleBaseAttributeId(attributeName, attributeType);
}
/**
* Creates and initializes an AttributeHistogram.
*
* @param attributeId attribute Id
*/
public AttributeHistogram(GoogleBaseAttributeId attributeId) {
this.attributeId = attributeId;
}
/**
* Gets the name of the attribute this histogram describes.
*
* @return attribute name
*/
public String getAttributeName() {
return attributeId.getName();
}
/**
* Gets the type of the attribute this histogram describes.
*
* @return attribute type
*/
public GoogleBaseAttributeType getAttributeType() {
return attributeId.getType();
}
/**
* Gets the name and type of the attribute this histogram describes.
*
* @return attribute id
*/
public GoogleBaseAttributeId getAttributeId() {
return attributeId;
}
/**
* Gets the total number of values found for this attribute in
* the result set for the query.
*
* This is not the total number of unique values, just the number
* of times this attribute was set.
*
* @return total number of values found for this attribute, always
* {@code >= sum(getValues().getCount())}
*/
public int getTotalValueCount() {
return totalValueCount;
}
/**
* Gets a list of unique values for the attribute and
* the count for these values.
*
* Not all unique values might be available. For some types,
* no values are ever available.
*
* @return a list of values and the number of time they
* were found in the result set, never null
*/
public List<? extends UniqueValue> getValues() {
return values;
}
/**
* Gets a list of unique values for the attribute and the count
* of these values, for values repeated at least a certain number
* of times.
*
* @param minimumCount minimum number of times the value should
* have been encountered in the result set to matter
* @return a list of values and the number of time they
* were found in the result set, never null
*/
public List<? extends UniqueValue> getValues(int minimumCount) {
if (minimumCount <= 0) {
return values;
}
List<UniqueValue> retval = new ArrayList<UniqueValue>(values.size());
for (UniqueValue value : values) {
if (value.getCount() >= minimumCount) {
retval.add(value);
}
}
return retval;
}
/**
* Adds a new value into the histogram.
* @param count number of time the value was found
* @param stringRepresentation
* @exception IllegalArgumentException unless count is greater than 0
* @exception NullPointerException if stringRepresentation is null
*/
public void addValue(int count, String stringRepresentation) {
values.add(new UniqueValue(count, stringRepresentation));
}
/**
* Sets the total value count.
*/
public void setTotalValueCount(int count) {
this.totalValueCount = count;
}
/**
* Sets attribute name and type.
*/
public void setAttributeId(String name, GoogleBaseAttributeType type) {
setAttributeId(new GoogleBaseAttributeId(name, type));
}
/**
* Sets attribute name and type.
*/
public void setAttributeId(GoogleBaseAttributeId attributeId) {
this.attributeId = attributeId;
}
/**
* Generates the XML representation for this tag.
*
* @param w XML writer
* @param extProfile extension profile
* @throws IOException thrown if there was an error writing to the XmlWriter
*/
public void generate(XmlWriter w, ExtensionProfile extProfile)
throws IOException {
if (attributeId == null) {
return;
}
List<XmlWriter.Attribute> attrs = new ArrayList<XmlWriter.Attribute>();
attrs.add(new XmlWriter.Attribute("name", attributeId.getName()));
if (attributeId.getType() != null) {
attrs.add(
new XmlWriter.Attribute("type", attributeId.getType().toString()));
}
if (totalValueCount > 0) {
attrs.add(
new XmlWriter.Attribute("count", Integer.toString(totalValueCount)));
}
w.startElement(GoogleBaseNamespaces.GM, "attribute", attrs, null);
if (values != null) {
w.startRepeatingElement();
for (AttributeHistogram.UniqueValue value : values) {
value.generate(w);
}
w.endRepeatingElement();
}
w.endElement();
}
/**
* Creates a handler for this gdata extension tag.
*
* @param extProfile {@inheritDoc}
* @param namespace {@inheritDoc}
* @param localName {@inheritDoc}
* @param attrs {@inheritDoc}
* @return {@inheritDoc}
* @throws ParseException {@inheritDoc}
* @throws IOException {@inheritDoc}
*/
public XmlParser.ElementHandler getHandler(ExtensionProfile extProfile,
String namespace, String localName, Attributes attrs)
throws ParseException, IOException {
AttributeHelper helper = new AttributeHelper(attrs);
GoogleBaseAttributeType type =
GoogleBaseAttributeType.getInstance(helper.consume("type", true));
setAttributeId(
new GoogleBaseAttributeId(helper.consume("name", true), type));
setTotalValueCount(helper.consumeInteger("count", false, 0));
helper.assertAllConsumed();
return new XmlParser.ElementHandler() {
@Override
public XmlParser.ElementHandler getChildHandler(String namespace,
String localName,
Attributes attrs)
throws ParseException, IOException {
if (namespace.equals(GoogleBaseNamespaces.GM_URI)
&& localName.equals("value")) {
return new AddValueHandler(attrs);
} else {
return super.getChildHandler(namespace, localName, attrs);
}
}
};
}
/**
* A value, as a string, and the number of times the value appears
* in the result set for the current query.
*/
public static class UniqueValue {
private final int count;
private final String value;
/**
* Creates a new UniqueValue object.
*
* @param count number of time the value was found
* @param value the value, as a string
*/
private UniqueValue(int count, String value) {
this.count = count;
this.value = value;
}
/**
* Gets the number of time this specific value was found.
*/
public int getCount() {
return count;
}
/**
* Gets the value itself, as a string.
*
* @return string representation for the value
*/
public String getValueAsString() {
return value;
}
/**
* Gets the value itself, as a string.
*/
public String toString() {
return value;
}
/**
* Generates the XML representation for this tag.
*
* @param w XML writer
*/
void generate(XmlWriter w) throws IOException {
List<XmlWriter.Attribute> attrs = null;
if (count > 0) {
attrs = Collections.singletonList(
new XmlWriter.Attribute("count", Integer.toString(count)));
}
w.simpleElement(GoogleBaseNamespaces.GM, "value", attrs, value);
}
}
/**
* Handles one gm:value tag and use it to add a value into a specific
* {@link com.google.api.gbase.client.AttributeHistogram}.
*/
private class AddValueHandler extends XmlParser.ElementHandler {
private final int count;
/**
* Creates an new handler for a gm:value tag.
*
* @param attrs XML attributes for the gm:value tag
*/
private AddValueHandler(Attributes attrs)
throws IOException, ParseException {
AttributeHelper helper = new AttributeHelper(attrs);
this.count = helper.consumeInteger("count", false, 0);
helper.assertAllConsumed();
}
@Override
public void processEndElement() throws ParseException {
String value = this.value;
if ("".equals(value)) {
value = null;
}
addValue(count, value);
}
}
}