// Copyright (C) 2006-2009 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.enterprise.connector.mock; import com.google.enterprise.connector.common.StringUtils; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import java.io.ByteArrayInputStream; import java.io.InputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; /** * Mock document property object. This encapsulates a typed name-value pair: the * name is a string, the value is also implemented as a string (for now), but we * remember the base type of the property, drawn from an enclosed enum: STRING, * DATE and INTEGER. * <p> * TODO(ziff): add a typed getter for the value */ public class MockRepositoryProperty { private static Logger LOGGER = Logger.getLogger(MockRepositoryProperty.class.getName()); // Constants used within raw ACL properties to delimit sections and label // scope. public static final String USER_SCOPE = "user"; public static final String GROUP_SCOPE = "group"; public static final int SCOPE_TYPE_SEP = ':'; public static final int SCOPE_ROLE_SEP = '='; /** * Enumeration for property carrier types */ public static class PropertyType implements Comparable<PropertyType> { private static int nextOrdinal = 0; private final int ordinal = nextOrdinal++; public static final PropertyType STRING = new PropertyType("string"); public static final PropertyType DATE = new PropertyType("date"); public static final PropertyType INTEGER = new PropertyType("integer"); public static final PropertyType STREAM = new PropertyType("stream"); public static final PropertyType UNDEFINED = new PropertyType("undefined"); private static final PropertyType[] PRIVATE_VALUES = {STRING, DATE, INTEGER, STREAM, UNDEFINED}; public static final List<PropertyType> Values = Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES)); private final String tag; private PropertyType(String t) { tag = t; } @Override public String toString() { return tag; } public static PropertyType findPropertyType(String tag) { if (tag == null) { return UNDEFINED; } for (int i = 0; i < PRIVATE_VALUES.length; i++) { if (PRIVATE_VALUES[i].tag.equals(tag)) { return PRIVATE_VALUES[i]; } } return UNDEFINED; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ordinal; return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } PropertyType other = (PropertyType) obj; if (ordinal != other.ordinal) { return false; } return true; } public int compareTo(PropertyType propertyType) { return ordinal - propertyType.ordinal; } } private String name; private PropertyType type; private String value; private InputStream streamValue; // used for streams private boolean streamRead; // indicates that stream has been used private List<String> multivalues; private boolean repeating; public MockRepositoryProperty(String name, PropertyType type, String value) { init(name, type, value); } public MockRepositoryProperty(String name, Object o) { if (o == null) { init(name, PropertyType.STRING, ""); } else if (o instanceof String) { String value = (String) o; if (value.startsWith("{") && value.endsWith("}")) { // this could be a json object - try to parse it as such JSONObject jo = null; try { jo = new JSONObject(value); init(name, jo); return; } catch (IllegalArgumentException e) { // it was a json object, but not the right kind to initialize a // property LOGGER.log(Level.FINEST, "Unable to initialize JSON String", e); } catch (JSONException e) { // it wasn't anything like a json object. it must be a regular string LOGGER.log(Level.FINEST, "Unable to parse as JSON String", e); } } init(name, PropertyType.STRING, value); } else if (o instanceof Integer) { Integer value = (Integer) o; init(name, PropertyType.INTEGER, value.toString()); } else if (o instanceof JSONObject) { JSONObject jo = (JSONObject) o; init(name, jo); } else if (o instanceof InputStream) { InputStream is = (InputStream) o; init(name, is); } else { throw new IllegalArgumentException( "Can't construct a MockRepositoryProperty from this: " + o); } } private void init(String name, PropertyType type, String value) { this.name = name; this.type = type; this.value = value; this.repeating = false; this.multivalues = null; } private void init(String name, JSONObject jo) { String s = jo.optString("type"); PropertyType type = PropertyType.findPropertyType(s); if (type == PropertyType.UNDEFINED) { throw new IllegalArgumentException("Type must be specified"); } Object v = jo.opt("value"); if (v instanceof String) { String value = (String) v; init(name, type, value); } else if (v instanceof Integer) { Integer value = (Integer) v; init(name, PropertyType.INTEGER, value.toString()); } else if (v instanceof JSONArray) { JSONArray ja = (JSONArray) v; this.name = name; this.type = type; this.repeating = true; this.multivalues = new ArrayList<String>(ja.length()); for (int i = 0; i < ja.length(); i++) { this.multivalues.add(ja.optString(i)); } } else { throw new IllegalArgumentException( "Can't make a property from this json object"); } } private void init(String name, InputStream is) { this.name = name; this.type = PropertyType.STREAM; this.streamValue = is; this.value = null; this.repeating = false; this.multivalues = null; } private String valuesToString() { if (!repeating) { return value; } else { return multivalues.toString(); } } @Override public String toString() { return name + "(" + type.toString() + "):" + (repeating ? valuesToString() : value); } public String getName() { return name; } public PropertyType getType() { return type; } public String getValue() { if (type.equals(PropertyType.STREAM)) { if (null == value) { value = StringUtils.streamToString(streamValue); streamRead = true; } return value; } if (!repeating) { return value; } if (multivalues == null || multivalues.size() < 1) { return ""; } return multivalues.get(0); } private final static String[] EMPTY_STRING_ARRAY = new String[0]; public String[] getValues() { if (!repeating) { return new String[] {getValue()}; } else { return multivalues.toArray(EMPTY_STRING_ARRAY); } } /** * Return the underlying InputStream. This method should only be called if * the type is PropertyType.STREAM. * * @return the underlying InputStream if object is of type STREAM */ public InputStream getStreamValue() { if (!type.equals(PropertyType.STREAM)) { throw new IllegalStateException("Can only call getStreamValue() on " + "properties of type PropertyType.STREAM"); } if (streamRead) { if (null != value) { return new ByteArrayInputStream(value.getBytes()); } else { throw new IllegalStateException("Cannot call getStreamValue() twice"); } } return streamValue; } public boolean isRepeating() { return repeating; } }