Repository: incubator-ignite Updated Branches: refs/heads/ignite-961 f7bb17cf5 -> 488ba5936
http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e6ba441d/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonGenerator.java ---------------------------------------------------------------------- diff --git a/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonGenerator.java b/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonGenerator.java new file mode 100644 index 0000000..3a90d38 --- /dev/null +++ b/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonGenerator.java @@ -0,0 +1,500 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.json; + +import javax.json.*; +import javax.json.stream.*; +import java.io.*; +import java.math.*; +import java.util.*; + +/** + * Json generator implementation. + */ +public class IgniteJsonGenerator implements JsonGenerator { + /** Writer. */ + private final BufferedWriter writer; + + private LinkedList<Element> ctx = new LinkedList(); + + /** + * @param writer Writer. + */ + public IgniteJsonGenerator(Writer writer) { + this.writer = new BufferedWriter(writer); + + ctx.push(new Element(Context.NONE, true)); + } + + /** {@inheritDoc} */ + @Override public JsonGenerator writeStartObject() { + try { + if (ctx.getLast().context() == Context.OBJECT || + (ctx.getLast().context() == Context.NONE && !ctx.getLast().isFirst())) + throw new JsonGenerationException("No name for object field."); + + writeComma(); + writer.write('{'); + + ctx.addLast(new Element(Context.OBJECT, true)); + + return this; + } + catch (IOException e) { + throw new JsonException("Writer fails.", e); + } + } + + /** {@inheritDoc} */ + @Override public JsonGenerator writeStartObject(String name) { + try { + if (ctx.getLast().context() != Context.OBJECT) + throw new JsonGenerationException("Object with name in not object scope."); + + writeComma(); + writeString(name); + writer.write(":"); + writer.write('{'); + + ctx.addLast(new Element(Context.OBJECT, true)); + + return this; + } + catch (IOException e) { + throw new JsonException("Writer fails.", e); + } + } + + /** {@inheritDoc} */ + @Override public JsonGenerator writeStartArray() { + try { + if (ctx.getLast().context() == Context.OBJECT || + (ctx.getLast().context() == Context.NONE && !ctx.getLast().isFirst())) + throw new JsonGenerationException("Array in object scope."); + + writeComma(); + writer.write("["); + + ctx.addLast(new Element(Context.ARRAY, true)); + + return this; + } + catch (IOException e) { + throw new JsonException("Writer fails.", e); + } + } + + /** {@inheritDoc} */ + @Override public JsonGenerator writeStartArray(String name) { + try { + if (ctx.getLast().context() != Context.OBJECT) + throw new JsonGenerationException("Array with name in not object scope."); + + writeComma(); + writeString(name); + writer.write(":"); + writer.write('['); + + ctx.addLast(new Element(Context.ARRAY, true)); + + return this; + } + catch (IOException e) { + throw new JsonException("Writer fails.", e); + } + } + + /** {@inheritDoc} */ + @Override public JsonGenerator write(String name, JsonValue val) { + if (ctx.getLast().context() != Context.OBJECT) + throw new JsonGenerationException("Json value with name in not object scope."); + + try { + switch (val.getValueType()) { + case ARRAY: { + JsonArray arr = (JsonArray) val; + + writeStartArray(name); + + for (JsonValue el : arr) + write(el); + + writeEnd(); + + break; + } + + case OBJECT: { + IgniteJsonObject o = (IgniteJsonObject) val; + + writeStartObject(name); + + for (Map.Entry<String, JsonValue> member : o.entrySet()) + write(member.getKey(), member.getValue()); + + writeEnd(); + + break; + } + + case STRING: { + JsonString str = (JsonString) val; + + write(name, str.getString()); + + break; + } + + case NUMBER: { + JsonNumber n = (JsonNumber) val; + + writeComma(); + writeString(name); + writer.write(":"); + writeString(n.toString()); + + break; + } + case TRUE: { + write(name, true); + + break; + } + + case FALSE: { + write(name, false); + + break; + } + + case NULL: { + writeNull(name); + + break; + } + } + return this; + } + catch (IOException e) { + throw new JsonException("Writer fails.", e); + } + } + + /** {@inheritDoc} */ + @Override public JsonGenerator write(String name, String val) { + return writeSimpleField(name, val); + } + + /** {@inheritDoc} */ + @Override public JsonGenerator write(String name, BigInteger val) { + return writeSimpleField(name, String.valueOf(val)); + } + + /** {@inheritDoc} */ + @Override public JsonGenerator write(String name, BigDecimal val) { + return writeSimpleField(name, String.valueOf(val)); + } + + /** {@inheritDoc} */ + @Override public JsonGenerator write(String name, int val) { + return writeSimpleField(name, String.valueOf(val)); + } + + /** {@inheritDoc} */ + @Override public JsonGenerator write(String name, long val) { + return writeSimpleField(name, String.valueOf(val)); + } + + /** {@inheritDoc} */ + @Override public JsonGenerator write(String name, double val) { + return writeSimpleField(name, String.valueOf(val)); + } + + /** {@inheritDoc} */ + @Override public JsonGenerator write(String name, boolean val) { + return writeSimpleField(name, String.valueOf(val)); + } + + /** {@inheritDoc} */ + @Override public JsonGenerator writeNull(String name) { + return writeSimpleField(name, "null"); + } + + /** {@inheritDoc} */ + @Override public JsonGenerator writeEnd() { + if (ctx.getLast().context() == Context.NONE) + throw new JsonGenerationException("Cannot call writeEnd in none context."); + + try { + if (ctx.getLast().context() == Context.ARRAY) + writer.write("]"); + + if (ctx.getLast().context() == Context.OBJECT) + writer.write("}"); + + ctx.removeLast(); + + return this; + } + catch(IOException e) { + throw new JsonException("Writer fails.", e); + } + } + + /** {@inheritDoc} */ + @Override public JsonGenerator write(JsonValue val) { + if (ctx.getLast().context() != Context.ARRAY) + throw new JsonGenerationException("Json value without name in not array scope."); + + try { + switch (val.getValueType()) { + case ARRAY: { + JsonArray arr = (JsonArray) val; + + writeStartArray(); + + for (JsonValue el : arr) + write(el); + + writeEnd(); + + break; + } + + case OBJECT: { + IgniteJsonObject o = (IgniteJsonObject) val; + + writeStartObject(); + + for (Map.Entry<String, JsonValue> member : o.entrySet()) + write(member.getKey(), member.getValue()); + + writeEnd(); + + break; + } + + case STRING: { + JsonString str = (JsonString) val; + + write(str.getString()); + + break; + } + + case NUMBER: { + JsonNumber n = (JsonNumber) val; + + writeComma(); + writeString(n.toString()); + + break; + } + case TRUE: { + write(true); + + break; + } + + case FALSE: { + write(false); + + break; + } + + case NULL: { + writeNull(); + + break; + } + } + return this; + } + catch (IOException e) { + throw new JsonException("Writer fails.", e); + } + } + + /** {@inheritDoc} */ + @Override public JsonGenerator write(String val) { + return writeSimpleArrayElement(val); + } + + /** {@inheritDoc} */ + @Override public JsonGenerator write(BigDecimal val) { + return writeSimpleArrayElement(String.valueOf(val)); + } + + /** {@inheritDoc} */ + @Override public JsonGenerator write(BigInteger val) { + return writeSimpleArrayElement(String.valueOf(val)); + } + + /** {@inheritDoc} */ + @Override public JsonGenerator write(int val) { + return writeSimpleArrayElement(String.valueOf(val)); + } + + /** {@inheritDoc} */ + @Override public JsonGenerator write(long val) { + return writeSimpleArrayElement(String.valueOf(val)); + } + + /** {@inheritDoc} */ + @Override public JsonGenerator write(double val) { + return writeSimpleArrayElement(String.valueOf(val)); + } + + /** {@inheritDoc} */ + @Override public JsonGenerator write(boolean val) { + return writeSimpleArrayElement(String.valueOf(val)); + } + + /** {@inheritDoc} */ + @Override public JsonGenerator writeNull() { + return writeSimpleArrayElement("null"); + } + + /** {@inheritDoc} */ + @Override public void close() { + try { + writer.close(); + } + catch (IOException e) { + throw new JsonException("Could not close writer.", e); + } + } + + /** {@inheritDoc} */ + @Override public void flush() { + try { + writer.flush(); + } + catch (IOException e) { + throw new JsonException("Could not flush buffer to writer.", e); + } + } + + /** + * Write comma if object is not first. + * + * @throws IOException If failed. + */ + private void writeComma() throws IOException{ + if (!ctx.getLast().isFirst()) + writer.write(","); + + ctx.getLast().isFirst = false; + } + + /** + * @param name Field name. + * @param val Field value. + */ + private JsonGenerator writeSimpleField(String name, String val) { + if (ctx.getLast().context() != Context.OBJECT) + throw new JsonGenerationException("String with name in not object scope."); + + try { + writeComma(); + writeString(name); + writer.write(":"); + writeString(val); + + return this; + } + catch (IOException e) { + throw new JsonException("Writer fails.", e); + } + } + + + /** + * @param val Field value. + */ + private JsonGenerator writeSimpleArrayElement(String val) { + if (ctx.getLast().context() != Context.ARRAY) + throw new JsonGenerationException("String without name in not array scope."); + + try { + writeComma(); + writeString(val); + + return this; + } + catch (IOException e) { + throw new JsonException("Writer fails.", e); + } + } + + /** + * @param str String to write. + * @throws IOException If failed. + * //TODO: escape string. + */ + private void writeString(String str) throws IOException { + writer.write(str); + } + + /** + * Generator element. + */ + private static class Element { + /** Context. */ + private Context ctx; + + /** First element flag. */ + private boolean isFirst; + + /** + * @param ctx Context. + * @param isFirst First element flag. + */ + public Element(Context ctx, boolean isFirst) { + this.ctx = ctx; + this.isFirst = isFirst; + } + + /** + * @return First element flag. + */ + public boolean isFirst() { + return isFirst; + } + + /** + * @return Context. + */ + public Context context() { + return ctx; + } + } + /** + * Context for writer. + */ + private enum Context { + /** Writing object. */ + OBJECT, + + /** Writing array. */ + ARRAY, + + /** Not in object or in array. */ + NONE + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e6ba441d/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonLocation.java ---------------------------------------------------------------------- diff --git a/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonLocation.java b/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonLocation.java new file mode 100644 index 0000000..feb5a4d --- /dev/null +++ b/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonLocation.java @@ -0,0 +1,60 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.json; + +import javax.json.stream.*; + +/** + * Json location implementation. + */ +public class IgniteJsonLocation implements JsonLocation { + /** Column number. */ + private final long col; + + /** Line number. */ + private final long line; + + /** Stream offset. */ + private final long off; + + /** + * @param line Line number. + * @param col Column number. + * @param streamOff Stream offset. + */ + IgniteJsonLocation(long line, long col, long streamOff) { + this.line = line; + this.col = col; + this.off = streamOff; + } + + /** {@inheritDoc} */ + @Override public long getLineNumber() { + return line; + } + + /** {@inheritDoc} */ + @Override public long getColumnNumber() { + return col; + } + + /** {@inheritDoc} */ + @Override public long getStreamOffset() { + return off; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e6ba441d/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonMessageFactory.java ---------------------------------------------------------------------- diff --git a/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonMessageFactory.java b/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonMessageFactory.java new file mode 100644 index 0000000..ff9f228 --- /dev/null +++ b/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonMessageFactory.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.json; + +import org.apache.ignite.plugin.extensions.communication.*; +import org.jetbrains.annotations.*; + +/** + * + */ +public class IgniteJsonMessageFactory implements MessageFactory { + /** {@inheritDoc} */ + @Nullable @Override public Message create(byte type) { + switch (type) { + case -23: + return new JsonCacheObject(); + } + + return null; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e6ba441d/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonNumber.java ---------------------------------------------------------------------- diff --git a/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonNumber.java b/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonNumber.java new file mode 100644 index 0000000..acbd50c --- /dev/null +++ b/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonNumber.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.json; + +import javax.json.*; +import java.io.*; +import java.math.*; + +/** + * Json number implementation. + * + * TODO IGNITE-962: optimize for int, long, double. + */ +public class IgniteJsonNumber implements JsonNumber, Serializable { + /** Value. */ + private final BigDecimal val; + + /** + * @param val Value. + */ + public IgniteJsonNumber(BigDecimal val){ + this.val = val; + } + + /** {@inheritDoc} */ + @Override public boolean isIntegral() { + return val != null && val.scale() == 0; + + } + + /** {@inheritDoc} */ + @Override public int intValue() { + return val.intValue(); + } + + /** {@inheritDoc} */ + @Override public int intValueExact() { + return val.intValueExact(); + } + + /** {@inheritDoc} */ + @Override public long longValue() { + return val.longValue(); + } + + /** {@inheritDoc} */ + @Override public long longValueExact() { + return val.longValueExact(); + } + + /** {@inheritDoc} */ + @Override public BigInteger bigIntegerValue() { + return val.toBigInteger(); + } + + /** {@inheritDoc} */ + @Override public BigInteger bigIntegerValueExact() { + return val.toBigIntegerExact(); + } + + /** {@inheritDoc} */ + @Override public double doubleValue() { + return val.doubleValue(); + } + + /** {@inheritDoc} */ + @Override public BigDecimal bigDecimalValue() { + return val; + } + + /** {@inheritDoc} */ + @Override public ValueType getValueType() { + return ValueType.NUMBER; + } + + /** {@inheritDoc} */ + @Override public String toString() { + return val.toString(); + } + + /** {@inheritDoc} */ + @Override public int hashCode() { + if (val == null) + return 0; + + return val.hashCode(); + } + + /** {@inheritDoc} */ + @Override public boolean equals(Object obj) { + if (obj == null || !(obj instanceof IgniteJsonNumber)) + return false; + + BigDecimal val0 = ((IgniteJsonNumber)obj).val; + + if (val == null) + return val0 == null; + + return val.equals(val0); + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e6ba441d/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonObject.java ---------------------------------------------------------------------- diff --git a/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonObject.java b/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonObject.java new file mode 100644 index 0000000..283b396 --- /dev/null +++ b/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonObject.java @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.json; + +import javax.json.*; +import java.io.*; +import java.util.*; + +/** + * IgniteJsonObject implementation. + */ +public class IgniteJsonObject extends HashMap<String, JsonValue> implements javax.json.JsonObject, Serializable { + /** + * @param val Map to store. + */ + public IgniteJsonObject(Map<String, JsonValue> val) { + super(val); + } + + /** {@inheritDoc} */ + @Override public JsonArray getJsonArray(String name) { + return (JsonArray)get(name); + } + + /** {@inheritDoc} */ + @Override public javax.json.JsonObject getJsonObject(String name) { + return (javax.json.JsonObject)get(name); + } + + /** {@inheritDoc} */ + @Override public JsonNumber getJsonNumber(String name) { + return (JsonNumber)get(name); + } + + /** {@inheritDoc} */ + @Override public JsonString getJsonString(String name) { + return (JsonString)get(name); + } + + /** {@inheritDoc} */ + @Override public String getString(String name) { + return getJsonString(name).getString(); + } + + /** {@inheritDoc} */ + @Override public String getString(String name, String dfltVal) { + try { + return getString(name); + } + catch (Exception e) { + return dfltVal; + } + } + + /** {@inheritDoc} */ + @Override public int getInt(String name) { + return getJsonNumber(name).intValue(); + } + + /** {@inheritDoc} */ + @Override public int getInt(String name, int dfltVal) { + try { + return getInt(name); + } + catch (Exception e) { + return dfltVal; + } + } + + /** {@inheritDoc} */ + @Override public boolean getBoolean(String name) { + JsonValue val = get(name); + + if (val.equals(JsonValue.TRUE)) + return true; + + if (val.equals(JsonValue.FALSE)) + return false; + + throw new ClassCastException(); + } + + /** {@inheritDoc} */ + @Override public boolean getBoolean(String name, boolean dfltVal) { + try { + return getBoolean(name); + } + catch (Exception e) { + return dfltVal; + } + } + + /** {@inheritDoc} */ + @Override public boolean isNull(String name) { + return get(name).equals(JsonValue.NULL); + } + + /** {@inheritDoc} */ + @Override public ValueType getValueType() { + return ValueType.OBJECT; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e6ba441d/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonObjectBuilder.java ---------------------------------------------------------------------- diff --git a/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonObjectBuilder.java b/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonObjectBuilder.java new file mode 100644 index 0000000..c5006fc --- /dev/null +++ b/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonObjectBuilder.java @@ -0,0 +1,141 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.json; + +import org.apache.ignite.internal.util.typedef.internal.*; + +import javax.json.*; +import java.math.*; +import java.util.*; + +/** + * Json object builder implementation. + */ +public class IgniteJsonObjectBuilder implements JsonObjectBuilder { + /** Json object map. */ + private Map<String, JsonValue> jsonMap = new HashMap<>(); + + /** {@inheritDoc} */ + @Override public JsonObjectBuilder add(String name, JsonValue val) { + A.notNull(name, "key", val, "value"); + + jsonMap.put(name, val); + + return this; + } + + /** {@inheritDoc} */ + @Override public JsonObjectBuilder add(String name, String val) { + A.notNull(name, "key", val, "value"); + + jsonMap.put(name, new IgniteJsonString(val)); + + return this; + } + + /** {@inheritDoc} */ + @Override public JsonObjectBuilder add(String name, BigInteger val) { + A.notNull(name, "key", val, "value"); + + //TODO: optimize for value + jsonMap.put(name, new IgniteJsonNumber(new BigDecimal(val))); + + return this; + } + + /** {@inheritDoc} */ + @Override public JsonObjectBuilder add(String name, BigDecimal val) { + A.notNull(name, "key", val, "value"); + + //TODO: optimize for value + jsonMap.put(name, new IgniteJsonNumber(val)); + + return this; + } + + /** {@inheritDoc} */ + @Override public JsonObjectBuilder add(String name, int val) { + A.notNull(name, "key"); + + //TODO: optimize for value + jsonMap.put(name, new IgniteJsonNumber(new BigDecimal(val))); + + return this; + } + + /** {@inheritDoc} */ + @Override public JsonObjectBuilder add(String name, long val) { + A.notNull(name, "key"); + + //TODO: optimize for value + jsonMap.put(name, new IgniteJsonNumber(new BigDecimal(val))); + + return this; + } + + /** {@inheritDoc} */ + @Override public JsonObjectBuilder add(String name, double val) { + A.notNull(name, "key"); + + //TODO: optimize for value + jsonMap.put(name, new IgniteJsonNumber(new BigDecimal(val))); + + return this; + } + + /** {@inheritDoc} */ + @Override public JsonObjectBuilder add(String name, boolean val) { + A.notNull(name, "key"); + + jsonMap.put(name, val ? JsonValue.TRUE : JsonValue.FALSE); + + return this; + } + + /** {@inheritDoc} */ + @Override public JsonObjectBuilder addNull(String name) { + A.notNull(name, "key"); + + jsonMap.put(name, JsonValue.NULL); + + return this; + } + + /** {@inheritDoc} */ + @Override public JsonObjectBuilder add(String name, JsonObjectBuilder bld) { + A.notNull(name, "key", bld, "value"); + + jsonMap.put(name, bld.build()); + + return this; + } + + /** {@inheritDoc} */ + @Override public JsonObjectBuilder add(String name, JsonArrayBuilder bld) { + A.notNull(name, "key", bld, "value"); + + jsonMap.put(name, bld.build()); + + return this; + } + + /** {@inheritDoc} */ + @Override public javax.json.JsonObject build() { + return new IgniteJsonObject(jsonMap); + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e6ba441d/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonProcessorImpl.java ---------------------------------------------------------------------- diff --git a/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonProcessorImpl.java b/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonProcessorImpl.java new file mode 100644 index 0000000..3e23b83 --- /dev/null +++ b/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonProcessorImpl.java @@ -0,0 +1,115 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.json; + +import org.apache.ignite.*; +import org.apache.ignite.internal.*; +import org.apache.ignite.internal.processors.*; +import org.apache.ignite.internal.processors.cache.*; +import org.jetbrains.annotations.*; + +import javax.json.*; + +/** + * + */ +public class IgniteJsonProcessorImpl extends GridProcessorAdapter implements IgniteJsonProcessor { + /** + * @param ctx Context. + */ + public IgniteJsonProcessorImpl(GridKernalContext ctx) { + super(ctx); + } + + /** {@inheritDoc} */ + @Override public KeyCacheObject toCacheKeyObject(CacheObjectContext ctx, Object obj, boolean userObj) { + if (obj instanceof JsonObject) + return new JsonCacheObject((JsonObject)obj); + + return null; + } + + /** {@inheritDoc} */ + @Nullable @Override public CacheObject toCacheObject(CacheObjectContext ctx, + @Nullable Object obj, + boolean userObj) { + if (obj instanceof JsonObject) + return new JsonCacheObject((JsonObject)obj); + + return null; + } + + /** {@inheritDoc} */ + @Override public boolean jsonType(Class<?> cls) { + return cls.equals(JsonObject.class); + } + + /** {@inheritDoc} */ + @Override public boolean jsonObject(Object obj) { + return obj instanceof JsonCacheObject || obj instanceof JsonObject; + } + + /** {@inheritDoc} */ + @Override public boolean hasField(Object obj, String fieldName) { + if (obj instanceof JsonObject) + return ((JsonObject)obj).containsKey(fieldName); + + return ((JsonCacheObject)obj).hasField(fieldName); + } + + /** {@inheritDoc} */ + @Override public Object field(Object obj, String fieldName) { + if (obj instanceof JsonObject) + return value((JsonObject) obj, fieldName); + + return ((JsonCacheObject)obj).field(fieldName); + } + + /** + * @param obj Object. + * @param fieldName Field name. + * @return Field value. + */ + static Object value(JsonObject obj, String fieldName) { + JsonValue jsonVal = obj.get(fieldName); + + if (jsonVal == null) + return null; + + switch (jsonVal.getValueType()) { + case FALSE: + return Boolean.FALSE; + + case TRUE: + return Boolean.TRUE; + + case STRING: + return ((JsonString)jsonVal).getString(); + + case NUMBER: + return ((JsonNumber)jsonVal).intValue(); + + case OBJECT: + return jsonVal; + + default: + throw new IgniteException("Unsupported type [field=" + fieldName + + ", type=" + jsonVal.getValueType() + ']'); + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e6ba441d/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonProvider.java ---------------------------------------------------------------------- diff --git a/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonProvider.java b/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonProvider.java new file mode 100644 index 0000000..dbcd8b8 --- /dev/null +++ b/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonProvider.java @@ -0,0 +1,104 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.json; + +import javax.json.*; +import javax.json.spi.*; +import javax.json.stream.*; +import java.io.*; +import java.util.*; + +/** + * Json provider implementation. + */ +public class IgniteJsonProvider extends JsonProvider { + /** {@inheritDoc} */ + @Override public JsonParser createParser(Reader reader) { + return null; + } + + /** {@inheritDoc} */ + @Override public JsonParser createParser(InputStream in) { + return null; + } + + /** {@inheritDoc} */ + @Override public JsonParserFactory createParserFactory(Map<String, ?> config) { + return null; + } + + /** {@inheritDoc} */ + @Override public JsonGenerator createGenerator(Writer writer) { + return new IgniteJsonGenerator(writer); + } + + /** {@inheritDoc} */ + @Override public JsonGenerator createGenerator(OutputStream out) { + return null; + } + + /** {@inheritDoc} */ + @Override public JsonGeneratorFactory createGeneratorFactory(Map<String, ?> config) { + return null; + } + + /** {@inheritDoc} */ + @Override public JsonReader createReader(Reader reader) { + return null; + } + + /** {@inheritDoc} */ + @Override public JsonReader createReader(InputStream in) { + return null; + } + + /** {@inheritDoc} */ + @Override public JsonWriter createWriter(Writer writer) { + return null; + } + + /** {@inheritDoc} */ + @Override public JsonWriter createWriter(OutputStream out) { + return null; + } + + /** {@inheritDoc} */ + @Override public JsonWriterFactory createWriterFactory(Map<String, ?> config) { + return null; + } + + /** {@inheritDoc} */ + @Override public JsonReaderFactory createReaderFactory(Map<String, ?> config) { + return null; + } + + /** {@inheritDoc} */ + @Override public JsonObjectBuilder createObjectBuilder() { + return new IgniteJsonObjectBuilder(); + } + + /** {@inheritDoc} */ + @Override public JsonArrayBuilder createArrayBuilder() { + return new IgniteJsonArrayBuilder(); + } + + /** {@inheritDoc} */ + @Override public JsonBuilderFactory createBuilderFactory(Map<String, ?> config) { + return null; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e6ba441d/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonString.java ---------------------------------------------------------------------- diff --git a/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonString.java b/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonString.java new file mode 100644 index 0000000..3adeb6b --- /dev/null +++ b/modules/json/src/main/java/org/apache/ignite/internal/processors/json/IgniteJsonString.java @@ -0,0 +1,77 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.json; + +import javax.json.*; +import java.io.*; + +/** + * Json string implementation. + */ +public class IgniteJsonString implements JsonString, Serializable { + /** Value. */ + private final String val; + + /** + * @param val Value. + */ + public IgniteJsonString(String val) { + this.val = val; + } + + /** {@inheritDoc} */ + @Override public String getString() { + return val; + } + + /** {@inheritDoc} */ + @Override public CharSequence getChars() { + return val; + } + + /** {@inheritDoc} */ + @Override public ValueType getValueType() { + return ValueType.STRING; + } + + /** {@inheritDoc} */ + @Override public int hashCode() { + if (val == null) + return 0; + + return val.hashCode(); + } + + /** {@inheritDoc} */ + @Override public boolean equals(Object obj) { + if (obj == null || !(obj instanceof JsonString)) + return false; + + JsonString other = (JsonString)obj; + + if (val == null) + return other.getString() == null; + + return val.equals(other.getString()); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return val; + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e6ba441d/modules/json/src/main/java/org/apache/ignite/internal/processors/json/JsonCacheObject.java ---------------------------------------------------------------------- diff --git a/modules/json/src/main/java/org/apache/ignite/internal/processors/json/JsonCacheObject.java b/modules/json/src/main/java/org/apache/ignite/internal/processors/json/JsonCacheObject.java new file mode 100644 index 0000000..9d631f5 --- /dev/null +++ b/modules/json/src/main/java/org/apache/ignite/internal/processors/json/JsonCacheObject.java @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.internal.processors.json; + +import org.apache.ignite.*; +import org.apache.ignite.internal.processors.cache.*; +import org.jetbrains.annotations.*; + +import javax.json.*; + +/** + * + */ +public class JsonCacheObject extends CacheObjectAdapter implements KeyCacheObject { + /** + * + */ + public JsonCacheObject() { + // No-op. + } + + /** + * @param obj Object. + */ + public JsonCacheObject(JsonObject obj) { + this.val = obj; + } + + /** {@inheritDoc} */ + @Override public byte type() { + return 10; + } + + /** {@inheritDoc} */ + @Nullable @Override public <T> T value(CacheObjectContext ctx, boolean cpy) { + return (T)val; + } + + /** {@inheritDoc} */ + @Override public byte[] valueBytes(CacheObjectContext ctx) throws IgniteCheckedException { + return valBytes; + } + + /** {@inheritDoc} */ + @Override public CacheObject prepareForCache(CacheObjectContext ctx) { + return this; + } + + /** {@inheritDoc} */ + @Override public void finishUnmarshal(CacheObjectContext ctx, ClassLoader ldr) throws IgniteCheckedException { + assert val != null || valBytes != null; + + if (val == null) + val = ctx.processor().unmarshal(ctx, valBytes, ldr); + } + + /** {@inheritDoc} */ + @Override public void prepareMarshal(CacheObjectContext ctx) throws IgniteCheckedException { + if (valBytes == null) + valBytes = ctx.processor().marshal(ctx, val); + } + + /** {@inheritDoc} */ + @Override public boolean internal() { + return false; + } + + /** {@inheritDoc} */ + @Override public byte directType() { + return -23; + } + + /** + * @param fieldName Field name. + * @return {@code True} if has field. + */ + boolean hasField(String fieldName) { + return ((IgniteJsonObject)val).containsKey(fieldName); + } + + /** + * @param fieldName Field name. + * @return Field value. + */ + Object field(String fieldName) { + return IgniteJsonProcessorImpl.value((JsonObject)val, fieldName); + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e6ba441d/modules/json/src/main/java/org/apache/ignite/json/IgniteJson.java ---------------------------------------------------------------------- diff --git a/modules/json/src/main/java/org/apache/ignite/json/IgniteJson.java b/modules/json/src/main/java/org/apache/ignite/json/IgniteJson.java new file mode 100644 index 0000000..f55f06d --- /dev/null +++ b/modules/json/src/main/java/org/apache/ignite/json/IgniteJson.java @@ -0,0 +1,36 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.ignite.json; + +import org.apache.ignite.*; +import org.apache.ignite.internal.processors.json.*; + +import javax.json.spi.*; + +/** + * + */ +public class IgniteJson { + /** + * @param ignite Ignite. + * @return Ignite JSON API provider. + */ + public static JsonProvider jsonProvider(Ignite ignite) { + return new IgniteJsonProvider(); + } +} http://git-wip-us.apache.org/repos/asf/incubator-ignite/blob/e6ba441d/modules/json/src/test/java/org/apache/ignite/internal/processors/json/IgniteJsonCacheTest.java ---------------------------------------------------------------------- diff --git a/modules/json/src/test/java/org/apache/ignite/internal/processors/json/IgniteJsonCacheTest.java b/modules/json/src/test/java/org/apache/ignite/internal/processors/json/IgniteJsonCacheTest.java new file mode 100644 index 0000000..6f710fc --- /dev/null +++ b/modules/json/src/test/java/org/apache/ignite/internal/processors/json/IgniteJsonCacheTest.java @@ -0,0 +1,194 @@ +package org.apache.ignite.internal.processors.json;/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +import org.apache.ignite.*; +import org.apache.ignite.cache.*; +import org.apache.ignite.cache.query.*; +import org.apache.ignite.configuration.*; +import org.apache.ignite.json.*; +import org.apache.ignite.spi.discovery.tcp.*; +import org.apache.ignite.spi.discovery.tcp.ipfinder.*; +import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.*; +import org.apache.ignite.testframework.junits.common.*; + +import javax.cache.*; +import javax.json.*; +import javax.json.spi.*; +import java.util.*; + +/** + * + */ +public class IgniteJsonCacheTest extends GridCommonAbstractTest { + /** */ + protected static TcpDiscoveryIpFinder ipFinder = new TcpDiscoveryVmIpFinder(true); + + /** */ + private boolean client; + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String gridName) throws Exception { + IgniteConfiguration cfg = super.getConfiguration(gridName); + + ((TcpDiscoverySpi)cfg.getDiscoverySpi()).setIpFinder(ipFinder); + + CacheConfiguration ccfg = new CacheConfiguration(); + + CacheTypeMetadata meta = new CacheTypeMetadata(); + + meta.setValueType(JsonObject.class); + + Map<String, Class<?>> ascFields = new HashMap<>(); + + ascFields.put("name", String.class); + ascFields.put("id", Integer.class); + ascFields.put("address.street", String.class); + + meta.setAscendingFields(ascFields); + + Map<String, Class<?>> qryFields = new HashMap<>(); + + qryFields.put("salary", Integer.class); + qryFields.put("address", JsonObject.class); + + meta.setQueryFields(qryFields); + + ccfg.setTypeMetadata(Collections.singleton(meta)); + + cfg.setCacheConfiguration(ccfg); + + cfg.setClientMode(client); + + return cfg; + } + + /** {@inheritDoc} */ + @Override protected void beforeTestsStarted() throws Exception { + super.beforeTestsStarted(); + + startGrid(0); + + client = true; + + startGrid(1); + } + + /** {@inheritDoc} */ + @Override protected void afterTestsStopped() throws Exception { + super.afterTestsStopped(); + + stopAllGrids(); + } + + /** + * @throws Exception If failed. + */ + public void testQuery() throws Exception { + IgniteCache<Integer, JsonObject> cache = ignite(1).cache(null); + + assertNotNull(cache); + + JsonProvider provider = IgniteJson.jsonProvider(ignite(1)); + + for (int i = 0; i < 10; i++) { + JsonObjectBuilder person = provider.createObjectBuilder(); + + person.add("name", "n-" + i); + person.add("salary", (i + 1) * 1000); + person.add("id", i); + + JsonObjectBuilder addr = provider.createObjectBuilder(); + + addr.add("street", "s-" + i); + + person.add("address", addr); + + JsonObject obj = person.build(); + + cache.put(i, obj); + } + + SqlQuery<Integer, JsonObject> nameQry = new SqlQuery<>(JsonObject.class, "name = ?"); + + nameQry.setArgs("n-5"); + + List<Cache.Entry<Integer, JsonObject>> res = cache.query(nameQry).getAll(); + + log.info("Res: " + res); + + assertEquals(1, res.size()); + + SqlQuery<Integer, JsonObject> idQry = new SqlQuery<>(JsonObject.class, "id > ?"); + + idQry.setArgs(5); + + res = cache.query(idQry).getAll(); + + log.info("Res: " + res); + + assertEquals(4, res.size()); + + SqlFieldsQuery avgQry = new SqlFieldsQuery("select avg(salary) from JsonObject"); + + log.info("Res: " + cache.query(avgQry).getAll()); + + SqlFieldsQuery fieldsQry = new SqlFieldsQuery("select name, salary from JsonObject where street = 's-3'"); + + log.info("Res: " + cache.query(fieldsQry).getAll()); + + fieldsQry = new SqlFieldsQuery("select address from JsonObject where street = 's-3'"); + + List<List<?>> fieldsRes = cache.query(fieldsQry).getAll(); + + assertEquals(1, fieldsRes.size()); + + List<?> fields = fieldsRes.get(0); + + assertEquals(1, fields.size()); + + JsonObject obj = (JsonObject)fields.get(0); + + log.info("Res: " + obj); + + assertEquals("s-3", obj.getString("street")); + + log.info("Res: " + + cache.query(new SqlFieldsQuery("select street from JsonObject where street = 's-3'")).getAll()); + } + + /** + * @throws Exception If failed. + */ + public void testJson() throws Exception { + IgniteCache<Integer, JsonObject> clientCache = ignite(1).cache(null); + + JsonProvider provider = IgniteJson.jsonProvider(ignite(1)); + + JsonObjectBuilder builder = provider.createObjectBuilder(); + + builder.add("name", "n1"); + builder.add("id", 1); + + JsonObject obj = builder.build(); + + clientCache.put(1, obj); + + obj = clientCache.get(1); + + log.info("Get: " + obj); + } +}