@Override public Volumes deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException { List<Volume> volumes = new ArrayList<Volume>(); ObjectCodec oc = jsonParser.getCodec(); JsonNode node = oc.readTree(jsonParser); for (Iterator<Map.Entry<String, JsonNode>> it = node.fields(); it.hasNext(); ) { Map.Entry<String, JsonNode> field = it.next(); if (!field.getValue().equals(NullNode.getInstance())) { String path = field.getKey(); Volume volume = new Volume(path); volumes.add(volume); } } return new Volumes(volumes.toArray(new Volume[0])); }
@Test public void test() throws JsonProcessingException, IOException { final Scope scope = new Scope(); final ObjectMapper mapper = new ObjectMapper(); scope.addFunction( "inc", 1, new JsonQueryFunction("inc", Arrays.asList("x"), JsonQuery.compile("x + 1"))); scope.addFunction( "fib", 1, new JsonQueryFunction( "fib", Arrays.asList("x"), JsonQuery.compile("if x == 0 then 0 elif x == 1 then 1 else fib(x-1) + fib(x-2) end"))); scope.addFunction( "fib", 0, new JsonQueryFunction("fib", Arrays.<String>asList(), JsonQuery.compile("fib(.)"), scope)); assertEquals( Arrays.asList(mapper.readTree("2")), JsonQuery.compile("inc(1)").apply(scope, NullNode.getInstance())); assertEquals( Arrays.asList(mapper.readTree("1")), JsonQuery.compile("fib(1)").apply(scope, NullNode.getInstance())); assertEquals( Arrays.asList(mapper.readTree("1")), JsonQuery.compile("fib(2)").apply(scope, NullNode.getInstance())); assertEquals( Arrays.asList(mapper.readTree("2")), JsonQuery.compile("fib(3)").apply(scope, NullNode.getInstance())); assertEquals( Arrays.asList(mapper.readTree("3")), JsonQuery.compile("fib(4)").apply(scope, NullNode.getInstance())); assertEquals( Arrays.asList(mapper.readTree("5")), JsonQuery.compile("fib(5)").apply(scope, NullNode.getInstance())); assertEquals( Arrays.asList(mapper.readTree("8")), JsonQuery.compile("fib").apply(scope, IntNode.valueOf(6))); }
/** * Finds the {@link Method} from the supplied {@link Set} that best matches the rest of the * arguments supplied and returns it as a {@link MethodAndArgs} class. * * @param methods the {@link Method}s * @param paramNames the parameter names * @param paramNodes the parameters for matching types * @return the {@link MethodAndArgs} */ @SuppressWarnings("deprecation") protected MethodAndArgs findBestMethodUsingParamNames( Set<Method> methods, Set<String> paramNames, ObjectNode paramNodes) { // determine param count int maxMatchingParams = -1; int maxMatchingParamTypes = -1; Method bestMethod = null; List<JsonRpcParam> bestAnnotations = null; for (Method method : methods) { // get parameter types List<Class<?>> parameterTypes = ReflectionUtil.getParameterTypes(method); // bail early if possible if (!allowExtraParams && paramNames.size() > parameterTypes.size()) { continue; } else if (!allowLessParams && paramNames.size() < parameterTypes.size()) { continue; } // list of params List<JsonRpcParam> annotations = new ArrayList<JsonRpcParam>(); // try the deprecated parameter first List<List<JsonRpcParamName>> depMethodAnnotations = ReflectionUtil.getParameterAnnotations(method, JsonRpcParamName.class); if (!depMethodAnnotations.isEmpty()) { for (List<JsonRpcParamName> annots : depMethodAnnotations) { if (annots.size() > 0) { final JsonRpcParamName annotation = annots.get(0); annotations.add( (JsonRpcParam) Proxy.newProxyInstance( getClass().getClassLoader(), new Class[] {JsonRpcParam.class}, new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (method.getName().equals("value")) { return annotation.value(); } throw new Exception("Unknown method: " + method.getName()); } })); } else { annots.add(null); } } } // now try the non-deprecated parameters List<List<JsonRpcParam>> methodAnnotations = ReflectionUtil.getParameterAnnotations(method, JsonRpcParam.class); if (!methodAnnotations.isEmpty()) { for (List<JsonRpcParam> annots : methodAnnotations) { if (annots.size() > 0) { annotations.add(annots.get(0)); } else { annots.add(null); } } } // count the matching params for this method int numMatchingParamTypes = 0; int numMatchingParams = 0; for (int i = 0; i < annotations.size(); i++) { // skip parameters that didn't have an annotation JsonRpcParam annotation = annotations.get(i); if (annotation == null) { continue; } // check for a match String paramName = annotation.value(); boolean hasParamName = paramNames.contains(paramName); if (hasParamName && isMatchingType(paramNodes.get(paramName), parameterTypes.get(i))) { numMatchingParamTypes++; numMatchingParams++; } else if (hasParamName) { numMatchingParams++; } } // check for exact param matches // bail early if possible if (!allowExtraParams && numMatchingParams > parameterTypes.size()) { continue; } else if (!allowLessParams && numMatchingParams < parameterTypes.size()) { continue; } // better match if (numMatchingParams > maxMatchingParams || (numMatchingParams == maxMatchingParams && numMatchingParamTypes > maxMatchingParamTypes)) { bestMethod = method; maxMatchingParams = numMatchingParams; maxMatchingParamTypes = numMatchingParamTypes; bestAnnotations = annotations; } } // bail early if (bestMethod == null) { return null; } // create return MethodAndArgs ret = new MethodAndArgs(); ret.method = bestMethod; // now fill arguments int numParameters = bestMethod.getParameterTypes().length; for (int i = 0; i < numParameters; i++) { JsonRpcParam param = bestAnnotations.get(i); if (param != null && paramNames.contains(param.value())) { ret.arguments.add(paramNodes.get(param.value())); } else { ret.arguments.add(NullNode.getInstance()); } } // return the method return ret; }
/** * Finds the {@link Method} from the supplied {@link Set} that best matches the rest of the * arguments supplied and returns it as a {@link MethodAndArgs} class. * * @param methods the {@link Method}s * @param paramCount the number of expect parameters * @param paramNodes the parameters for matching types * @return the {@link MethodAndArgs} */ protected MethodAndArgs findBestMethodUsingParamIndexes( Set<Method> methods, int paramCount, ArrayNode paramNodes) { // get param count int numParams = paramNodes != null && !paramNodes.isNull() ? paramNodes.size() : 0; // determine param count int bestParamNumDiff = Integer.MAX_VALUE; Set<Method> matchedMethods = new HashSet<Method>(); // check every method for (Method method : methods) { // get parameter types Class<?>[] paramTypes = method.getParameterTypes(); int paramNumDiff = paramTypes.length - paramCount; // we've already found a better match if (Math.abs(paramNumDiff) > Math.abs(bestParamNumDiff)) { continue; // we don't allow extra params } else if (!allowExtraParams && paramNumDiff < 0 || !allowLessParams && paramNumDiff > 0) { continue; // check the parameters } else { if (Math.abs(paramNumDiff) < Math.abs(bestParamNumDiff)) { matchedMethods.clear(); } matchedMethods.add(method); bestParamNumDiff = paramNumDiff; continue; } } // bail early if (matchedMethods.isEmpty()) { return null; } // now narrow it down to the best method // based on argument types Method bestMethod = null; if (matchedMethods.size() == 1 || numParams == 0) { bestMethod = matchedMethods.iterator().next(); } else { // check the matching methods for // matching parameter types int mostMatches = -1; for (Method method : matchedMethods) { List<Class<?>> parameterTypes = ReflectionUtil.getParameterTypes(method); int numMatches = 0; for (int i = 0; i < parameterTypes.size() && i < numParams; i++) { if (isMatchingType(paramNodes.get(i), parameterTypes.get(i))) { numMatches++; } } if (numMatches > mostMatches) { mostMatches = numMatches; bestMethod = method; } } } // create return MethodAndArgs ret = new MethodAndArgs(); ret.method = bestMethod; // now fill arguments int numParameters = bestMethod.getParameterTypes().length; for (int i = 0; i < numParameters; i++) { if (i < numParams) { ret.arguments.add(paramNodes.get(i)); } else { ret.arguments.add(NullNode.getInstance()); } } // return the method return ret; }
/** @author henrik lundgren */ public final class ContinuousChangesFeed implements ChangesFeed, Runnable { private static final AtomicInteger THREAD_COUNT = new AtomicInteger(); private static final Logger LOG = LoggerFactory.getLogger(ContinuousChangesFeed.class); private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); private static final DocumentChange INTERRUPT_MARKER = new StdDocumentChange(NullNode.getInstance()); private static final Set<Class<?>> INTERRUPTED_EXCEPTION_TYPES = new HashSet<Class<?>>(); static { INTERRUPTED_EXCEPTION_TYPES.add(InterruptedException.class); INTERRUPTED_EXCEPTION_TYPES.add(InterruptedIOException.class); } private final BlockingQueue<DocumentChange> changes = new LinkedBlockingQueue<DocumentChange>(100); private final BufferedReader reader; private final Thread thread = new Thread(this); private volatile boolean shouldRun = true; private final HttpResponse httpResponse; public ContinuousChangesFeed(String dbName, HttpResponse httpResponse) { this.httpResponse = httpResponse; try { reader = new BufferedReader(new InputStreamReader(httpResponse.getContent(), "UTF-8")); thread.setName( String.format( "ektorp-%s-changes-listening-thread-%s", dbName, THREAD_COUNT.getAndIncrement())); thread.start(); } catch (UnsupportedEncodingException e) { throw Exceptions.propagate(e); } } public DocumentChange next() throws InterruptedException { assertRunningState(); DocumentChange c = changes.take(); checkIfInterrupted(c); return c; } public DocumentChange poll() throws InterruptedException { assertRunningState(); DocumentChange c = changes.poll(); checkIfInterrupted(c); return c; } public DocumentChange next(long timeout, TimeUnit unit) throws InterruptedException { assertRunningState(); DocumentChange c = changes.poll(timeout, unit); checkIfInterrupted(c); return c; } private void assertRunningState() { if (!isAlive()) { throw new IllegalStateException("Changes feed is not alive"); } } private void checkIfInterrupted(DocumentChange c) throws InterruptedException { if (c == INTERRUPT_MARKER || (!shouldRun && changes.isEmpty())) { throw new InterruptedException(); } } public void cancel() { LOG.debug("Feed cancelled"); shouldRun = false; thread.interrupt(); } @edu.umd.cs.findbugs.annotations.SuppressWarnings(value = "RV_RETURN_VALUE_IGNORED_BAD_PRACTICE") private void sendInterruptMarker() { LOG.debug("Sending interrupt marker in order to interrupt feed consumer"); changes.offer(INTERRUPT_MARKER); } public boolean isAlive() { return thread.isAlive(); } public int queueSize() { return changes.size(); } public void run() { try { String line = reader.readLine(); while (shouldRun && line != null) { if (line.length() > 0) { handleChange(line); } else { handleHeartbeat(); } line = reader.readLine(); } String reason = !shouldRun ? "Cancelled" : "EOF"; LOG.info("Changes feed stopped. Reason: " + reason); } catch (Exception e) { handleException(e); } finally { sendInterruptMarker(); httpResponse.abort(); try { reader.close(); } catch (IOException e) { } } } private void handleChange(String line) throws IOException, InterruptedException, JsonParseException, JsonMappingException { changes.put(new StdDocumentChange(OBJECT_MAPPER.readTree(line))); } private void handleHeartbeat() { LOG.debug("Got heartbeat from DB"); } private void handleException(Exception e) { if (INTERRUPTED_EXCEPTION_TYPES.contains(e.getClass())) { LOG.info("Changes feed was interrupted"); } else { LOG.error("Caught exception while listening to changes feed:", e); } } }
public NullLiteral() { super(NullNode.getInstance()); }
/** Adds a variable to the current scope. */ private void addVariable(String name) { JsonNode node = currentNode.path(name); if (node.isMissingNode()) { currentNode.put(name, NullNode.getInstance()); } }
@JsonValue public NullNode value() { return NullNode.getInstance(); }