Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: 57411278ecfa67a55dd00156667f699c6fa08720 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
/*******************************************************************************
 * Copyright (c) 2005, 2011 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.equinox.metatype.impl;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.*;
import org.eclipse.equinox.metatype.EquinoxAttributeDefinition;
import org.eclipse.equinox.metatype.EquinoxObjectClassDefinition;
import org.osgi.framework.Bundle;

/**
 * Implementation of ObjectClassDefinition
 */
public class ObjectClassDefinitionImpl extends LocalizationElement implements EquinoxObjectClassDefinition, Cloneable {
	public static final char LOCALE_SEP = '_';

	private static final Comparator<Icon> iconComparator = new Comparator<Icon>() {
		public int compare(Icon icon1, Icon icon2) {
			return icon1.getIconSize().compareTo(icon2.getIconSize());
		}
	};

	private final String _name;
	private final String _id;
	private final String _description;
	private final int _type;
	private final Vector<AttributeDefinitionImpl> _required = new Vector<AttributeDefinitionImpl>(7);
	private final Vector<AttributeDefinitionImpl> _optional = new Vector<AttributeDefinitionImpl>(7);
	private final ExtendableHelper helper;

	// @GuardedBy("this")
	private List<Icon> icons;

	/*
	 * Constructor of class ObjectClassDefinitionImpl.
	 */
	public ObjectClassDefinitionImpl(String name, String description, String id, String localization, Map<String, Map<String, String>> extensionAttributes) {
		this(name, description, id, 0, localization, new ExtendableHelper(extensionAttributes));
	}

	/*
	 * Constructor of class ObjectClassDefinitionImpl.
	 */
	public ObjectClassDefinitionImpl(String name, String description, String id, int type, String localization, ExtendableHelper helper) {
		this._name = name;
		this._id = id;
		this._description = description;
		this._type = type;
		this._localization = localization;
		this.helper = helper;
	}

	/*
	 * 
	 */
	public synchronized Object clone() {

		ObjectClassDefinitionImpl ocd = new ObjectClassDefinitionImpl(_name, _description, _id, _type, _localization, helper);
		for (int i = 0; i < _required.size(); i++) {
			AttributeDefinitionImpl ad = _required.elementAt(i);
			ocd.addAttributeDefinition((AttributeDefinitionImpl) ad.clone(), true);
		}
		for (int i = 0; i < _optional.size(); i++) {
			AttributeDefinitionImpl ad = _optional.elementAt(i);
			ocd.addAttributeDefinition((AttributeDefinitionImpl) ad.clone(), false);
		}
		if (icons != null)
			ocd.setIcons(new ArrayList<Icon>(icons));
		return ocd;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.osgi.service.metatype.ObjectClassDefinition#getName()
	 */
	public String getName() {
		return getLocalized(_name);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.osgi.service.metatype.ObjectClassDefinition#getID()
	 */
	public String getID() {
		return _id;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.osgi.service.metatype.ObjectClassDefinition#getDescription()
	 */
	public String getDescription() {
		return getLocalized(_description);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.osgi.service.metatype.ObjectClassDefinition#getAttributeDefinitions(int)
	 */
	public EquinoxAttributeDefinition[] getAttributeDefinitions(int filter) {

		EquinoxAttributeDefinition[] atts;
		switch (filter) {
			case REQUIRED :
				atts = new EquinoxAttributeDefinition[_required.size()];
				_required.toArray(atts);
				return atts;
			case OPTIONAL :
				atts = new EquinoxAttributeDefinition[_optional.size()];
				_optional.toArray(atts);
				return atts;
			case ALL :
			default :
				atts = new EquinoxAttributeDefinition[_required.size() + _optional.size()];
				Enumeration<AttributeDefinitionImpl> e = _required.elements();
				int i = 0;
				while (e.hasMoreElements()) {
					atts[i] = e.nextElement();
					i++;
				}
				e = _optional.elements();
				while (e.hasMoreElements()) {
					atts[i] = e.nextElement();
					i++;
				}
				return atts;
		}
	}

	/*
	 * Method to add one new AD to ObjectClassDefinition.
	 */
	void addAttributeDefinition(AttributeDefinitionImpl ad, boolean isRequired) {

		if (isRequired) {
			_required.addElement(ad);
		} else {
			_optional.addElement(ad);
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.osgi.service.metatype.ObjectClassDefinition#getIcon(int)
	 */
	public synchronized InputStream getIcon(int sizeHint) throws IOException {
		// The parameter simply represents a requested size. This method should never return null if an
		// icon exists.
		// Temporary icon to hold the requested size for use in binary search comparator.
		Icon icon = new Icon(null, sizeHint, null);
		@SuppressWarnings("hiding")
		// Use a local reference to the icon list to be sure we don't suddenly start using a new one.
		List<Icon> icons = this.icons;
		// Icons will be null if none were specified.
		if (icons == null)
			return null;
		int index = Collections.binarySearch(icons, icon, iconComparator);
		if (index < 0) {
			// If the index is less than zero, there wasn't an exact match.
			// Compute the insertion point. This will be the index of the first icon whose 
			// size was greater than the requested size, or the list's length if there were none.
			int insertionPoint = -(index + 1);
			Icon lessThan = insertionPoint == 0 ? null : icons.get(insertionPoint - 1);
			Icon greaterThan = insertionPoint == icons.size() ? null : icons.get(insertionPoint);
			if (lessThan == null)
				// There were no icons whose size was smaller than the requested size.
				icon = greaterThan;
			else if (greaterThan == null)
				// There were no icons whose size was greater than the requested size.
				icon = lessThan;
			else {
				// There was at least one icon with a smaller size and at least one with
				// a greater size than the requested size. Compute the average to see which one to choose.
				int average = (greaterThan.getIconSize() + lessThan.getIconSize()) / 2;
				if (sizeHint < average)
					// The smaller icon is closer to the requested size.
					icon = lessThan;
				else
					// The larger icon is closer to the requested size.
					icon = greaterThan;
			}
		} else
			// The index was greater than or equal to zero, indicating the index of an exact match.
			icon = icons.get(index);
		Bundle b = icon.getIconBundle();
		URL[] urls = FragmentUtils.findEntries(b, getLocalized(icon.getIconName()));
		if (urls != null && urls.length > 0) {
			return urls[0].openStream();
		}
		return null;
	}

	synchronized void setIcons(List<Icon> icons) {
		// Do nothing if icons is null or empty.
		if (icons == null || icons.isEmpty())
			return;
		// Prepare the list of icons for binary searches as in getIcon(int).
		Collections.sort(icons, iconComparator);
		// Make the list unmodifiable for safe binary searches without copying.
		// We assume the caller makes no modifications to the list.
		this.icons = Collections.unmodifiableList(icons);
	}

	/**
	 * Method to set the resource bundle for this OCD and all its ADs.
	 */
	void setResourceBundle(String assignedLocale, Bundle bundle) {

		_rb = getResourceBundle(assignedLocale, bundle);

		Enumeration<AttributeDefinitionImpl> allADReqs = _required.elements();
		while (allADReqs.hasMoreElements()) {
			AttributeDefinitionImpl ad = allADReqs.nextElement();
			ad.setResourceBundle(_rb);
		}

		Enumeration<AttributeDefinitionImpl> allADOpts = _optional.elements();
		while (allADOpts.hasMoreElements()) {
			AttributeDefinitionImpl ad = allADOpts.nextElement();
			ad.setResourceBundle(_rb);
		}
	}

	/*
	 * Internal Method - to get resource bundle.
	 */
	private ResourceBundle getResourceBundle(String locale, final Bundle bundle) {
		// Determine the base name of the bundle localization property files.
		// If the <MetaData> 'localization' attribute was not specified,
		// use the Bundle-Localization manifest header value instead if it exists.
		String resourceBase = _localization != null ? _localization : MetaTypeProviderImpl.getBundleLocalization(bundle);

		// There are seven searching candidates possible:
		// baseName + 
		//		"_" + language1 + "_" + country1 + "_" + variation1	+ ".properties"
		// or	"_" + language1 + "_" + country1					+ ".properties"
		// or	"_" + language1										+ ".properties"
		// or	"_" + language2 + "_" + country2 + "_" + variation2	+ ".properties"
		// or	"_" + language2 + "_" + country2					+ ".properties"
		// or	"_" + language2										+ ".properties"
		// or	""													+ ".properties"
		//
		// Where language1[_country1[_variation1]] is the requested locale,
		// and language2[_country2[_variation2]] is the default locale.

		String[] searchCandidates = new String[7];

		// Candidates from passed locale:
		if (locale != null && locale.length() > 0) {
			int idx1_first = locale.indexOf(LOCALE_SEP);
			if (idx1_first == -1) {
				// locale has only language.
				searchCandidates[2] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + locale;
			} else {
				// locale has at least language and country.
				searchCandidates[2] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + locale.substring(0, idx1_first);
				int idx1_second = locale.indexOf(LOCALE_SEP, idx1_first + 1);
				if (idx1_second == -1) {
					// locale just has both language and country.
					searchCandidates[1] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + locale;
				} else {
					// locale has language, country, and variation all.
					searchCandidates[1] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + locale.substring(0, idx1_second);
					searchCandidates[0] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + locale;
				}
			}
		}

		// Candidates from Locale.getDefault():
		String defaultLocale = Locale.getDefault().toString();
		int idx2_first = defaultLocale.indexOf(LOCALE_SEP);
		int idx2_second = defaultLocale.indexOf(LOCALE_SEP, idx2_first + 1);
		if (idx2_second != -1) {
			// default-locale is format of [language]_[country]_variation.
			searchCandidates[3] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + defaultLocale;
			if (searchCandidates[3].equalsIgnoreCase(searchCandidates[0])) {
				searchCandidates[3] = null;
			}
		}
		if ((idx2_first != -1) && (idx2_second != idx2_first + 1)) {
			// default-locale is format of [language]_country[_variation].
			searchCandidates[4] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + ((idx2_second == -1) ? defaultLocale : defaultLocale.substring(0, idx2_second));
			if (searchCandidates[4].equalsIgnoreCase(searchCandidates[1])) {
				searchCandidates[4] = null;
			}
		}
		if ((idx2_first == -1) && (defaultLocale.length() > 0)) {
			// default-locale has only language.
			searchCandidates[5] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + defaultLocale;
		} else if (idx2_first > 0) {
			// default-locale is format of language_[...].
			searchCandidates[5] = MetaTypeProviderImpl.RESOURCE_FILE_CONN + defaultLocale.substring(0, idx2_first);
		}
		if (searchCandidates[5] != null && searchCandidates[5].equalsIgnoreCase(searchCandidates[2])) {
			searchCandidates[5] = null;
		}

		// The final candidate.
		searchCandidates[6] = ""; //$NON-NLS-1$

		URL resourceUrl = null;
		URL[] urls = null;

		for (int idx = 0; (idx < searchCandidates.length) && (resourceUrl == null); idx++) {
			urls = (searchCandidates[idx] == null ? null : FragmentUtils.findEntries(bundle, resourceBase + searchCandidates[idx] + MetaTypeProviderImpl.RESOURCE_FILE_EXT));
			if (urls != null && urls.length > 0)
				resourceUrl = urls[0];
		}

		if (resourceUrl != null) {
			try {
				return new PropertyResourceBundle(resourceUrl.openStream());
			} catch (IOException ioe) {
				// Exception when creating PropertyResourceBundle object.
			}
		}
		return null;
	}

	public Map<String, String> getExtensionAttributes(String schema) {
		return helper.getExtensionAttributes(schema);
	}

	public Set<String> getExtensionUris() {
		return helper.getExtensionUris();
	}
}

Back to the top