/* * 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.activemq.artemis.utils; import java.util.ArrayList; import java.util.List; /** * This class converts a JMS selector expression into an ActiveMQ Artemis core filter expression. * * JMS selector and ActiveMQ Artemis filters use the same syntax but have different identifiers. * * We basically just need to replace the JMS header and property Identifier names * with the corresponding ActiveMQ Artemis field and header Identifier names. * * We must be careful not to substitute any literals, or identifiers whose name contains the name * of one we want to substitute. * * This makes it less trivial than a simple search and replace. */ public class SelectorTranslator { public static String convertToActiveMQFilterString(final String selectorString) { if (selectorString == null) { return null; } // First convert any JMS header identifiers String filterString = SelectorTranslator.parse(selectorString, "JMSDeliveryMode", "AMQDurable"); filterString = SelectorTranslator.parse(filterString, "'PERSISTENT'", "'DURABLE'"); filterString = SelectorTranslator.parse(filterString, "'NON_PERSISTENT'", "'NON_DURABLE'"); filterString = SelectorTranslator.parse(filterString, "JMSPriority", "AMQPriority"); filterString = SelectorTranslator.parse(filterString, "JMSTimestamp", "AMQTimestamp"); filterString = SelectorTranslator.parse(filterString, "JMSMessageID", "AMQUserID"); filterString = SelectorTranslator.parse(filterString, "JMSExpiration", "AMQExpiration"); return filterString; } private static String parse(final String input, final String match, final String replace) { final char quote = '\''; boolean inQuote = false; int matchPos = 0; List<Integer> positions = new ArrayList<>(); boolean replaceInQuotes = match.charAt(0) == quote; for (int i = 0; i < input.length(); i++) { char c = input.charAt(i); if (c == quote) { inQuote = !inQuote; } if ((!inQuote || replaceInQuotes) && c == match.charAt(matchPos)) { matchPos++; if (matchPos == match.length()) { boolean matched = true; // Check that name is not part of another identifier name // Check character after match if (i < input.length() - 1 && Character.isJavaIdentifierPart(input.charAt(i + 1))) { matched = false; } // Check character before match int posBeforeStart = i - match.length(); if (posBeforeStart >= 0 && Character.isJavaIdentifierPart(input.charAt(posBeforeStart))) { matched = false; } if (matched) { positions.add(i - match.length() + 1); } // check previous character too matchPos = 0; } } else { matchPos = 0; } } if (!positions.isEmpty()) { StringBuffer buff = new StringBuffer(); int startPos = 0; for (int pos : positions) { String substr = input.substring(startPos, pos); buff.append(substr); buff.append(replace); startPos = pos + match.length(); } if (startPos < input.length()) { buff.append(input.substring(startPos, input.length())); } return buff.toString(); } else { return input; } } }