/** * ============LICENSE_START==================================================== * org.onap.aaf * =========================================================================== * Copyright (c) 2018 AT&T Intellectual Property. All rights reserved. * =========================================================================== * 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. * ============LICENSE_END==================================================== * */ package org.onap.aaf.auth.rserv; import java.util.HashMap; import java.util.Map; import java.util.Set; /** * This path matching algorithm avoids using split strings during the critical transactional run-time. By pre-analyzing the * content at "set Param" time, and storing data in an array-index model which presumably is done once and at the beginning, * we can match in much less time when it actually counts. * * @author Jonathan * */ public class Match { private Map params; private byte[][] values; private Integer[] vars; private boolean wildcard; /* * These two methods are pairs of searching performance for variables Spark Style. * setParams evaluates the target path, and sets a HashMap that will return an Integer. * the Keys are both :key and key so that there will be no string operations during * a transaction * * For the Integer, if the High Order is 0, then it is just one value. If High Order >0, then it is * a multi-field option, i.e. ending with a wild-card. */ public Match(String path) { params = new HashMap<>(); if (path!=null) { String[] pa = path.split("/"); values = new byte[pa.length][]; vars = new Integer[pa.length]; int val = 0; String key; for (int i=0;i1) { /* remove * from value */ int newlength = values[i].length-1; byte[] real = new byte[newlength]; System.arraycopy(values[i],0,real,0,newlength); values[i]=real; } else { vars[i]=0; // this is actually a variable, if it only contains a "*" } } } } } } /* * This is the second of the param evaluation functions. First, we look up to see if there is * any reference by key in the params Map created by the above. * * The resulting Integer, if not null, is split high/low order into start and end. * We evaluate the string for '/', rather than splitting into String[] to avoid the time/mem needed * We traverse to the proper field number for slash, evaluate the end (whether wild card or no), * and return the substring. * * The result is something less than .003 milliseconds per evaluation * */ public String param(String path,String key) { Integer val = params.get(key); // :key or key if (val!=null) { int start = val & 0xFFFF; int end = (val >> 16) & 0xFFFF; int idx = -1; int i; for (i=0;i=lastField) { // checking here allows there to be a non-functional ending / rv = false; break; } if (values[field]==null) { // it's a variable, just look for /s if (wildcard && field==lastField-1) return true;// we've made it this far. We accept all remaining characters Integer val = vars[field]; int start = val & 0xFFFF; int end = (val >> 16) & 0xFFFF; if (end==0)end=start+1; int k = i; for (int j=start; ji)i=k-1; // if we've incremented, have to accommodate the outer for loop incrementing as well fieldMatched = false; // reset fieldIdx = 0; } else { if (pabytes[i]=='/') { // end of field, eval if Field is matched // if double slash, check if supposed to be empty if (fieldIdx==0 && values[field].length==0) { fieldMatched = true; } rv = fieldMatched && ++field getParamNames() { return params.keySet(); } }