001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.isis.viewer.restfulobjects.rendering; 020 021import java.util.Collections; 022import java.util.List; 023 024import org.apache.isis.commons.internal.collections._Lists; 025import org.apache.isis.viewer.restfulobjects.applib.JsonRepresentation; 026import org.apache.isis.viewer.restfulobjects.applib.util.PathNode; 027import org.apache.isis.viewer.restfulobjects.rendering.util.FollowSpecUtil; 028 029public final class LinkFollowSpecs { 030 031 public static final LinkFollowSpecs create(final List<List<String>> links) { 032 final List<List<PathNode>> specs = FollowSpecUtil.asFollowSpecs(links); 033 return new LinkFollowSpecs(specs, Mode.FOLLOWING, null); 034 } 035 036 private enum Mode { 037 FOLLOWING, TERMINATED; 038 } 039 040 private final List<List<PathNode>> pathSpecs; 041 private final Mode mode; 042 // don't care about the key, just the criteria 043 private final List<PathNode> criteriaSpecs; 044 045 private LinkFollowSpecs(final List<List<PathNode>> pathSpecs, final Mode mode, final List<PathNode> criteriaSpecs) { 046 this.pathSpecs = pathSpecs; 047 this.mode = mode; 048 this.criteriaSpecs = criteriaSpecs; 049 } 050 051 /** 052 * A little algebra... 053 */ 054 public LinkFollowSpecs follow(final String pathTemplate, final Object... args) { 055 final String path = String.format(pathTemplate, args); 056 if (path == null) { 057 return terminated(); 058 } 059 if (mode == Mode.TERMINATED) { 060 return terminated(); 061 } 062 final PathNode candidate = PathNode.parse(path); 063 if (mode == Mode.FOLLOWING) { 064 List<List<PathNode>> remainingPathSpecs = _Lists.newArrayList(); 065 List<PathNode> firstSpecs = _Lists.newArrayList(); 066 for(List<PathNode> spec: pathSpecs) { 067 if(spec.isEmpty()) { 068 continue; 069 } 070 PathNode first = spec.get(0); 071 if(candidate.equals(first)) { 072 List<PathNode> remaining = spec.subList(1, spec.size()); 073 firstSpecs.add(first); 074 remainingPathSpecs.add(remaining); 075 } 076 } 077 if(!remainingPathSpecs.isEmpty()) { 078 return new LinkFollowSpecs(remainingPathSpecs, Mode.FOLLOWING, firstSpecs); 079 } 080 return terminated(); 081 } 082 return terminated(); 083 } 084 085 private static LinkFollowSpecs terminated() { 086 return new LinkFollowSpecs(Collections.<List<PathNode>>emptyList(), Mode.TERMINATED, Collections.<PathNode>emptyList()); 087 } 088 089 /** 090 * Not public API; use {@link #matches(JsonRepresentation)}. 091 */ 092 boolean isFollowing() { 093 return mode == Mode.FOLLOWING; 094 } 095 096 public boolean isTerminated() { 097 return mode == Mode.TERMINATED; 098 } 099 100 /** 101 * Ensure that every key present in the provided map matches the criterium. 102 * 103 * <p> 104 * Any keys in the criterium are ignored (these were matched on during the 105 * {@link #follow(String, Object...)} call). 106 */ 107 public boolean matches(final JsonRepresentation jsonRepr) { 108 if (!isFollowing()) { 109 return false; 110 } 111 if(criteriaSpecs == null) { 112 return true; 113 } 114 for (PathNode criteriaSpec : criteriaSpecs) { 115 if(criteriaSpec.matches(jsonRepr)) { 116 return true; 117 } 118 } 119 return false; 120 } 121 122 @Override 123 public String toString() { 124 return mode + " : " + criteriaSpecs + " : " + pathSpecs; 125 } 126 127}