| /* |
| * 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 |
| * |
| * https://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.tools.ant.property; |
| |
| import java.util.Collections; |
| import java.util.Deque; |
| import java.util.HashSet; |
| import java.util.LinkedList; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.concurrent.ConcurrentHashMap; |
| import java.util.stream.Collector; |
| |
| import org.apache.tools.ant.PropertyHelper; |
| |
| /** |
| * A stack of local property maps. |
| * There is a map for each scope (target, sequential, macro). |
| * @since Ant 1.8.0 |
| */ |
| public class LocalPropertyStack { |
| private final Deque<Map<String, Object>> stack = new LinkedList<>(); |
| private final Object LOCK = new Object(); |
| |
| // -------------------------------------------------- |
| // |
| // Local property adding and scoping |
| // |
| // -------------------------------------------------- |
| |
| /** |
| * Add a local property. |
| * @param property the name of the local property. |
| */ |
| public void addLocal(String property) { |
| synchronized (LOCK) { |
| Map<String, Object> map = stack.peek(); |
| if (map != null) { |
| map.put(property, NullReturn.NULL); |
| } |
| } |
| } |
| |
| /** |
| * Enter the local scope. |
| */ |
| public void enterScope() { |
| synchronized (LOCK) { |
| stack.addFirst(new ConcurrentHashMap<>()); |
| } |
| } |
| |
| /** |
| * Exit the local scope. |
| */ |
| public void exitScope() { |
| synchronized (LOCK) { |
| stack.removeFirst().clear(); |
| } |
| } |
| |
| // -------------------------------------------------- |
| // |
| // Copy - used in parallel to make a new stack |
| // |
| // -------------------------------------------------- |
| |
| /** |
| * Copy the stack for a parallel thread. |
| * @return a copy. |
| */ |
| public LocalPropertyStack copy() { |
| synchronized (LOCK) { |
| LocalPropertyStack ret = new LocalPropertyStack(); |
| ret.stack.addAll(stack); |
| return ret; |
| } |
| } |
| |
| // -------------------------------------------------- |
| // |
| // PropertyHelper delegate methods |
| // |
| // -------------------------------------------------- |
| |
| /** |
| * Evaluate a property. |
| * @param property the property's String "identifier". |
| * @param helper the invoking PropertyHelper. |
| * @return Object value. |
| */ |
| public Object evaluate(String property, PropertyHelper helper) { |
| synchronized (LOCK) { |
| for (Map<String, Object> map : stack) { |
| Object ret = map.get(property); |
| if (ret != null) { |
| return ret; |
| } |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Set a *new" property. |
| * @param property the property's String "identifier". |
| * @param value the value to set. |
| * @param propertyHelper the invoking PropertyHelper. |
| * @return true if this entity 'owns' the property. |
| */ |
| public boolean setNew( |
| String property, Object value, PropertyHelper propertyHelper) { |
| Map<String, Object> map = getMapForProperty(property); |
| if (map == null) { |
| return false; |
| } |
| Object currValue = map.get(property); |
| if (currValue == NullReturn.NULL) { |
| map.put(property, value); |
| } |
| return true; |
| } |
| |
| /** |
| * Set a property. |
| * @param property the property's String "identifier". |
| * @param value the value to set. |
| * @param propertyHelper the invoking PropertyHelper. |
| * @return true if this entity 'owns' the property. |
| */ |
| public boolean set(String property, Object value, PropertyHelper propertyHelper) { |
| Map<String, Object> map = getMapForProperty(property); |
| if (map == null) { |
| return false; |
| } |
| map.put(property, value); |
| return true; |
| } |
| |
| /** |
| * Returns the names of all known local properties. |
| * @since 1.10.9 |
| * @return the names of all known local properties. |
| */ |
| public Set<String> getPropertyNames() { |
| final Set<String> names = stack.stream().map(Map::keySet) |
| .collect(Collector.of(() -> new HashSet<String>(), |
| (ns, ks) -> ns.addAll(ks), |
| (ns1, ns2) -> { ns1.addAll(ns2); return ns1; }, |
| Collector.Characteristics.UNORDERED, Collector.Characteristics.IDENTITY_FINISH)); |
| return Collections.unmodifiableSet(names); |
| } |
| |
| private Map<String, Object> getMapForProperty(String property) { |
| synchronized (LOCK) { |
| for (Map<String, Object> map : stack) { |
| if (map.get(property) != null) { |
| return map; |
| } |
| } |
| } |
| return null; |
| } |
| } |
| |