All Downloads are FREE. Search and download functionalities are using the official Maven repository.

aQute.bnd.osgi.Instructions Maven / Gradle / Ivy

The newest version!
package aQute.bnd.osgi;

import static java.util.Objects.requireNonNull;
import static java.util.stream.Collectors.toSet;

import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Function;

import aQute.bnd.header.Attrs;
import aQute.bnd.header.Attrs.Type;
import aQute.bnd.header.Parameters;
import aQute.bnd.stream.MapStream;
import aQute.lib.collections.MultiMap;
import aQute.lib.io.IO;

public class Instructions implements Map {
	private LinkedHashMap	map;
	public static Instructions					ALWAYS	= new Instructions();
	static Map				EMPTY	= Collections.emptyMap();

	public Instructions(Instructions other) {
		if (other.map != null && !other.map.isEmpty()) {
			map = new LinkedHashMap<>(other.map);
		}
	}

	public Instructions(Collection other) {
		if (other != null)
			for (String s : other) {
				put(new Instruction(s), null);
			}
	}

	public Instructions() {}

	public Instructions(Parameters contained) {
		append(contained);
	}

	public Instructions(String h) {
		this(new Parameters(h));
	}

	@Override
	public void clear() {
		map.clear();
	}

	public boolean containsKey(Instruction name) {
		if (map == null)
			return false;

		return map.containsKey(name);
	}

	@Override
	@Deprecated
	public boolean containsKey(Object name) {
		assert name instanceof Instruction;
		if (map == null)
			return false;

		return map.containsKey(name);
	}

	public boolean containsValue(Attrs value) {
		if (map == null)
			return false;

		return map.containsValue(value);
	}

	@Override
	@Deprecated
	public boolean containsValue(Object value) {
		assert value instanceof Attrs;
		if (map == null)
			return false;

		return map.containsValue(value);
	}

	@Override
	public Set> entrySet() {
		if (map == null)
			return EMPTY.entrySet();

		return map.entrySet();
	}

	public MapStream stream() {
		return MapStream.of(this);
	}

	@Override
	@Deprecated
	public Attrs get(Object key) {
		assert key instanceof Instruction;
		if (map == null)
			return null;

		return map.get(key);
	}

	public Attrs get(Instruction key) {
		if (map == null)
			return null;

		return map.get(key);
	}

	@Override
	public boolean isEmpty() {
		return map == null || map.isEmpty();
	}

	@Override
	public Set keySet() {
		if (map == null)
			return EMPTY.keySet();

		return map.keySet();
	}

	@Override
	public Attrs put(Instruction key, Attrs value) {
		if (map == null)
			map = new LinkedHashMap<>();

		return map.put(key, value);
	}

	@Override
	public void putAll(Map map) {
		if (this.map == null) {
			if (map.isEmpty())
				return;
			this.map = new LinkedHashMap<>();
		}
		this.map.putAll(map);
	}

	@Override
	@Deprecated
	public Attrs remove(Object var0) {
		assert var0 instanceof Instruction;
		if (map == null)
			return null;

		return map.remove(var0);
	}

	public Attrs remove(Instruction var0) {
		if (map == null)
			return null;
		return map.remove(var0);
	}

	@Override
	public int size() {
		if (map == null)
			return 0;
		return map.size();
	}

	@Override
	public Collection values() {
		if (map == null)
			return EMPTY.values();

		return map.values();
	}

	@Override
	public String toString() {
		return map == null ? "{}" : map.toString();
	}

	public void append(Parameters other) {
		other.stream()
			.mapKey(Instruction::new)
			.forEachOrdered(this::put);
	}

	public void appendIfAbsent(Parameters other) {
		Set present = keySet().stream()
			.map(Instruction::getInput)
			.collect(toSet());

		other.stream()
			.filterKey(k -> !present.contains(k))
			.mapKey(Instruction::new)
			.forEachOrdered(this::put);
	}

	public  Collection select(Collection set, boolean emptyIsAll) {
		return select(set, null, emptyIsAll);
	}

	public  Collection select(Collection set, Set unused, boolean emptyIsAll) {
		List input = new ArrayList<>(set);
		if (emptyIsAll && isEmpty())
			return input;

		List result = new ArrayList<>();

		for (Instruction instruction : keySet()) {
			boolean used = false;
			for (Iterator o = input.iterator(); o.hasNext();) {
				T oo = o.next();
				String s = oo.toString();
				if (instruction.matches(s)) {
					if (!instruction.isNegated())
						result.add(oo);
					o.remove();
					used = true;
				}
			}
			if (!used && unused != null)
				unused.add(instruction);
		}
		return result;
	}

	public  Collection reject(Collection set) {
		List input = new ArrayList<>(set);
		List result = new ArrayList<>();

		for (Instruction instruction : keySet()) {
			for (Iterator o = input.iterator(); o.hasNext();) {
				T oo = o.next();
				String s = oo.toString();
				if (instruction.matches(s)) {
					if (instruction.isNegated())
						result.add(oo);
					o.remove();
				} else
					result.add(oo);

			}
		}
		return result;
	}

	public Instruction matcher(String value) {
		for (Instruction i : keySet()) {
			if (i.matches(value)) {
				return i;
			}
		}
		return null;
	}

	public Instruction finder(String value) {
		for (Instruction i : keySet()) {
			if (i.finds(value)) {
				return i;
			}
		}
		return null;
	}

	public boolean matches(String value) {
		if (isEmpty())
			return true;

		Instruction instr = matcher(value);
		if (instr == null || instr.isNegated())
			return false; // we deny this one explicitly
		return true;
	}

	public MapStream matchesStream(String value) {
		requireNonNull(value);
		AtomicBoolean negated = new AtomicBoolean(false);
		return stream().filterKey(instruction -> {
			if (negated.get() || !instruction.matches(value)) {
				return false;
			}
			if (instruction.isNegated()) {
				negated.set(true);
				return false;
			}
			return true;
		});
	}

	/**
	 * Turn this Instructions into a map of File -> Attrs. You can specify a
	 * base directory, which will match all files in that directory against the
	 * specification or you can use literal instructions to get files from
	 * anywhere.
	 * 

* A mapping function can be provided to rename literal names. This was * added to map '.' and '' to 'bnd.bnd'. However, this can be generally * useful. * * @param base The directory to list files from. * @param mapper Maps the literal names. * @return The map that links files to attributes */ public Map> select(File base, Function mapper, Set missing) { requireNonNull(mapper); MultiMap result = new MultiMap<>(); // // We allow literals to be specified so that we can actually include // files from anywhere in the file system // for (java.util.Map.Entry instr : entrySet()) { if (instr.getKey() .isLiteral() && !instr.getKey() .isNegated()) { String name = mapper.apply(instr.getKey() .getLiteral()); if (name == null) continue; File f = IO.getFile(base, name); if (f.isFile()) result.add(f, instr.getValue()); else if (missing != null) missing.add(instr.getKey()); } } // // Iterator over the found files and match them against this // if (base != null) { nextFile: for (File f : IO.listFiles(base)) { for (Entry instr : entrySet()) { if (instr.getKey() .isLiteral()) continue; String name = f.getName(); if (instr.getKey() .matches(name)) { if (!instr.getKey() .isNegated()) result.add(f, instr.getValue()); continue nextFile; } } } } return result; } /** * Match the instruction against the parameters and merge the attributes if * matches. Remove any negated instructions. Literal unmatched instructions * are not added * * @param parameters the parameters to decorate */ public void decorate(Parameters parameters) { decorate(parameters, false); } /** * Match the instruction against the parameters and merge the attributes if * matches. Remove any negated instructions. Literal unmatched instructions * are added if the addLiterals is true * * @param parameters the parameters to decorate * @param addLiterals add literals to the output */ public void decorate(Parameters parameters, boolean addLiterals) { List unused = addLiterals ? new ArrayList<>(keySet()) : Collections.emptyList(); for (Iterator> it = parameters.entrySet() .iterator(); it.hasNext();) { Entry next = it.next(); String key = Processor.removeDuplicateMarker(next.getKey()); Instruction matching = matcher(key); if (matching != null) { if (addLiterals) { int index = unused.indexOf(matching); if (index >= 0) { unused.set(index, null); } } if (matching.isNegated()) it.remove(); else { decorateAttrs(next.getValue(), get(matching)); } } } // Add the literals if (addLiterals) { Parameters copy = null; for (ListIterator li = unused.listIterator(); li.hasNext();) { Instruction ins = li.next(); if ((ins == null) || !ins.isLiteral() || ins.isNegated()) { if (copy != null) { // end inserting at beginning parameters.putAll(copy); copy = null; } continue; } // ins is a non-negated literal if (li.previousIndex() == 0) { // if first item, start insert at beginning copy = new Parameters(parameters); parameters.clear(); } parameters.put(ins.getLiteral(), decorateAttrs(new Attrs(), get(ins))); } if (copy != null) { parameters.putAll(copy); } } } private Attrs decorateAttrs(Attrs target, Attrs decoration) { decoration.forEach((key, value) -> { Type type = decoration.getType(key); if (key.length() > 1) { switch (key.charAt(0)) { case '!' : key = key.substring(1); target.remove(key); return; case '~' : key = key.substring(1); if (target.containsKey(key)) { return; } break; default : break; } } target.put(key, type, value); }); return target; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy