1 /*******************************************************************************
2  * Copyright (c) 2005, 2018 Cognos Incorporated, IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     Cognos Incorporated - initial API and implementation
13  *     IBM Corporation - bug fixes and enhancements
14  *******************************************************************************/
15 package org.eclipse.equinox.internal.cm;
16 
17 import java.io.Serializable;
18 import java.lang.reflect.Array;
19 import java.util.*;
20 import java.util.Map.Entry;
21 
22 /**
23  * ConfigurationDictionary holds the actual configuration data and meets the various comparison
24  * requirements of the Configuration Admin Service specification.
25  */
26 
27 public class ConfigurationDictionary extends Dictionary<String, Object> implements Serializable {
28 
29 	private static final long serialVersionUID = -3583299578203095532L;
30 	private static final Collection<Class<?>> simples = Arrays.asList(new Class<?>[] {String.class, Integer.class, Long.class, Float.class, Double.class, Byte.class, Short.class, Character.class, Boolean.class});
31 	private static final Collection<Class<?>> simpleArrays = Arrays.asList(new Class<?>[] {String[].class, Integer[].class, Long[].class, Float[].class, Double[].class, Byte[].class, Short[].class, Character[].class, Boolean[].class});
32 	private static final Collection<Class<?>> primitiveArrays = Arrays.asList(new Class<?>[] {long[].class, int[].class, short[].class, char[].class, byte[].class, double[].class, float[].class, boolean[].class});
33 
34 	static class CaseInsensitiveStringComparator implements Comparator<String>, Serializable {
35 		private static final long serialVersionUID = 6501536810492374044L;
36 
37 		@Override
compare(String s1, String s2)38 		public int compare(String s1, String s2) {
39 			return (s1).compareToIgnoreCase(s2);
40 		}
41 	}
42 
43 	protected final Map<String, Object> configurationProperties = Collections.synchronizedMap(new TreeMap<>(new CaseInsensitiveStringComparator()));
44 
validateValue(Object value)45 	private static void validateValue(Object value) {
46 		Class<?> clazz = value.getClass();
47 
48 		// Is it in the set of simple types
49 		if (simples.contains(clazz))
50 			return;
51 
52 		// Is it an array of primitives or simples
53 		if (simpleArrays.contains(clazz) || primitiveArrays.contains(clazz))
54 			return;
55 
56 		// Is it a Collection of simples
57 		if (value instanceof Collection) {
58 			for (Object simple : (Collection<?>) value) {
59 				Class<?> containedClazz = simple.getClass();
60 				if (!simples.contains(containedClazz)) {
61 					throw new IllegalArgumentException(containedClazz.getName() + " in " + clazz.getName()); //$NON-NLS-1$
62 				}
63 			}
64 			return;
65 		}
66 		throw new IllegalArgumentException(clazz.getName());
67 	}
68 
69 	@Override
elements()70 	public Enumeration<Object> elements() {
71 		return new Enumeration<Object>() {
72 			final Iterator<Object> valuesIterator = configurationProperties.values().iterator();
73 
74 			@Override
75 			public boolean hasMoreElements() {
76 				return valuesIterator.hasNext();
77 			}
78 
79 			@Override
80 			public Object nextElement() {
81 				return valuesIterator.next();
82 			}
83 		};
84 	}
85 
86 	@Override
get(Object key)87 	public Object get(Object key) {
88 		if (key == null)
89 			throw new NullPointerException();
90 		return configurationProperties.get(key);
91 	}
92 
93 	@Override
isEmpty()94 	public boolean isEmpty() {
95 		return configurationProperties.isEmpty();
96 	}
97 
98 	@Override
keys()99 	public Enumeration<String> keys() {
100 		return new Enumeration<String>() {
101 			Iterator<String> keysIterator = configurationProperties.keySet().iterator();
102 
103 			@Override
104 			public boolean hasMoreElements() {
105 				return keysIterator.hasNext();
106 			}
107 
108 			@Override
109 			public String nextElement() {
110 				return keysIterator.next();
111 			}
112 		};
113 	}
114 
115 	@Override
116 	public Object put(String key, Object value) {
117 		if (key == null || value == null)
118 			throw new NullPointerException();
119 
120 		// Will throw an illegal argument exception if not a valid configuration property type
121 		validateValue(value);
122 
123 		return configurationProperties.put(key, value);
124 	}
125 
126 	@Override
127 	public Object remove(Object key) {
128 		if (key == null)
129 			throw new NullPointerException();
130 		return configurationProperties.remove(key);
131 	}
132 
133 	@Override
134 	public int size() {
135 		return configurationProperties.size();
136 	}
137 
138 	ConfigurationDictionary copy() {
139 		ConfigurationDictionary result = new ConfigurationDictionary();
140 		for (Entry<String, Object> entry : configurationProperties.entrySet()) {
141 			String key = entry.getKey();
142 			Object value = entry.getValue();
143 			if (value.getClass().isArray()) {
144 				int arrayLength = Array.getLength(value);
145 				Object copyOfArray = Array.newInstance(value.getClass().getComponentType(), arrayLength);
146 				System.arraycopy(value, 0, copyOfArray, 0, arrayLength);
147 				result.configurationProperties.put(key, copyOfArray);
148 			} else if (value instanceof Collection)
149 				result.configurationProperties.put(key, new ArrayList<>((Collection<?>) value));
150 			else
151 				result.configurationProperties.put(key, value);
152 		}
153 		return result;
154 	}
155 }
156