View Javadoc

1   /*
2    * Copyright (c) 2006 Stiftung Deutsches Elektronen-Synchroton,
3    * Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY.
4    *
5    * THIS SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "../AS IS" BASIS.
6    * WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
7    * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR PARTICULAR PURPOSE AND
8    * NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
9    * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
10   * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
11   * THE USE OR OTHER DEALINGS IN THE SOFTWARE. SHOULD THE SOFTWARE PROVE DEFECTIVE
12   * IN ANY RESPECT, THE USER ASSUMES THE COST OF ANY NECESSARY SERVICING, REPAIR OR
13   * CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE.
14   * NO USE OF ANY SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
15   * DESY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
16   * OR MODIFICATIONS.
17   * THE FULL LICENSE SPECIFYING FOR THE SOFTWARE THE REDISTRIBUTION, MODIFICATION,
18   * USAGE AND OTHER RIGHTS AND OBLIGATIONS IS INCLUDED WITH THE DISTRIBUTION OF THIS
19   * PROJECT IN THE FILE LICENSE.HTML. IF THE LICENSE IS NOT INCLUDED YOU MAY FIND A COPY
20   * AT HTTP://WWW.DESY.DE/LEGAL/LICENSE.HTM
21   */
22  
23  package de.desy.acop.displayers.selector;
24  
25  import java.beans.PropertyChangeListener;
26  import java.beans.PropertyChangeSupport;
27  import java.util.ArrayList;
28  import java.util.Arrays;
29  
30  import com.cosylab.util.ListenerList;
31  import com.cosylab.util.NumericStringComparator;
32  
33  import de.desy.acop.transport.AccessMode;
34  import de.desy.tine.queryUtils.TQuery;
35  
36  /**
37   * <code>Selector</code> is a non-visual bean which performs all queries for
38   * remote property names. The queries are bean started by selecting the
39   * higher level parameter. First the access protocol should be selected, which
40   * triggers the context query. Upon selecting the context, subsystem query will
41   * be performed etc. 
42   * <p>
43   * All queries made in this bean are synchronous. However one cannot explicitely
44   * demand a list of parameters if the query has not been completed. After each
45   * of the queries completes it will set the parameters to the property
46   * whic will fire a PropertyChangeEvent notifying the listeners that one
47   * of the properties has changed. In addition to that selector also fires 
48   * <code>QueryEvent</code>s each time a query was started or finished.
49   * </p>
50   * 
51   * @author <a href="mailto:jaka.bobnar@cosylab.com">Jaka Bobnar</a>
52   * @version $Id: Templates.xml,v 1.10 2004/01/13 16:17:13 jbobnar Exp $
53   * @see TQuery
54   */
55  public class Selector {
56  
57  	
58  	public static void main(String[] args) {
59  		String[] prop = TQuery.getContexts();
60  		System.out.println(prop);
61  		System.exit(0);
62      }
63  	
64  	public static final String PROTOCOL_TINE = "TINE";
65  			
66  	private PropertyChangeSupport propertyChangeSupport;
67  	private String selectedSubSystem = null;
68  	private String[] availableSubsystems = null;
69  	private String[] availableContexts = null;
70  	private String selectedContext = null;
71  	private String[] availableServers = null;
72  	private String selectedServer = null;
73  	private String[] availableDevices = null;
74  	private String selectedDevice = null;
75  	private String[] availableProperties = null;
76  	private String selectedProperty = null;
77  	private String[] availableProtcols = new String[]{PROTOCOL_TINE};
78  	private String selectedProtocol = null;
79  	private int accessRate = 1000;
80  	private AccessMode accessMode = AccessMode.POLL;
81  	private volatile int queries=0;
82  	
83  	private boolean showStockProperties = false;
84  	
85  	private boolean propertyPrecedence = false;
86  	private boolean devicePrecedence = false;
87  	
88  	private ListenerList queryListeners = new ListenerList(QueryListener.class);
89  	private ListenerList exceptionListeners = new ListenerList(ExceptionListener.class);
90  	
91  	private NumericStringComparator comparator = new NumericStringComparator();
92  	
93  	private int searchingContext = 0;
94  	private int searchingServer = 0;
95  	private int searchingDevice = 0;
96  	private int searchingProperty = 0;
97  	private int searchingSubsystem = 0;
98  	
99  	/**
100 	 * Constructs a new Selector.
101 	 *
102 	 */
103 	public Selector() {
104 		super();
105 		propertyChangeSupport = new PropertyChangeSupport(this);
106 	}
107 	
108 	private void performContextQuery() {
109 		try {
110 			searchingContext++;
111 	    	setAvailableContexts(null);
112 	    	setAvailableServers(null);
113 	    	setAvailableDevices(null);
114 	    	setAvailableProperties(null);
115 	    	setAvailableContexts(TQuery.getContexts());
116 		} catch (Exception e) {
117 			handleException(e);
118 		} finally {
119 			searchingContext--;
120 			checkIfIsWorking();
121 		}
122 	}
123 	
124 	private void performServerQuery() {
125 		try {
126 			searchingServer++;
127 	    	setAvailableProperties(null);
128 	    	setAvailableDevices(null);
129 	    	setAvailableServers(null);
130 			if (selectedContext != null) {
131 				setAvailableServers(TQuery.getDeviceServers(selectedContext, selectedSubSystem));
132 			}
133 		} catch (Exception e) {
134 			handleException(e);
135 		} finally {
136 			searchingServer--;
137 			checkIfIsWorking();
138 		}
139 	}
140 	
141 	private void performSubsystemQuery() {
142 		try {
143 			searchingSubsystem++;
144 	    	setAvailableProperties(null);
145 	    	setAvailableDevices(null);
146 	    	setAvailableServers(null);
147 	    	setAvailableSubsystems(null);
148 			if (selectedContext != null) {
149 				setAvailableSubsystems(TQuery.getDeviceSubsystems(selectedContext));
150 			}
151 		} catch (Exception e) {
152 			handleException(e);
153 		} finally {
154 			searchingSubsystem--;
155 			checkIfIsWorking();
156 		}
157 	}
158 	
159 	private void performDeviceNameQuery(boolean clearAvailableProperties) {
160 		try {
161 			searchingDevice++;
162 	    	if (clearAvailableProperties)
163 	    		setAvailableProperties(null);
164 			if (!(selectedContext == null || selectedServer == null))  {
165 				
166 				String[] devices = null;
167 				
168 				if (!propertyPrecedence) {
169 					devices = TQuery.getDeviceNames(selectedContext, selectedServer);
170 					if (TQuery.devices_have_query_function) 
171 						propertyPrecedence = true;
172 			    } else {
173 		        	devices = TQuery.getDeviceNames(selectedContext, selectedServer, selectedProperty);
174 			    }
175 
176 				setAvailableDevices(devices);
177 			} else {
178 				setAvailableDevices(null);
179 			}
180 			
181 			
182 		} catch (Exception e) {
183 			handleException(e);
184 		} finally {
185 			searchingDevice--;
186 			checkIfIsWorking();
187 		}
188 	}
189 	
190 	private void performPropertyNameQuery(String wildCharProp) {
191     	try {
192     		searchingProperty++;
193         	if (selectedContext == null || selectedServer == null) return;
194     		
195     		String[] properties = TQuery.getDeviceProperties(selectedContext, selectedServer, selectedDevice, wildCharProp);
196     		
197     		if (TQuery.properties_have_query_function) {
198     	        devicePrecedence = true;
199     	        propertyPrecedence = false;
200     	    }
201     		
202     		String[] stocks = new String[0];
203     		if (showStockProperties) {
204     			stocks = TQuery.getStockProperties(selectedContext, selectedServer);
205     		}
206     		
207     		if (properties != null) {
208 	    		int offset = properties.length;
209 	    		String[] available = new String[offset + stocks.length];
210 	    		for (int i = 0; i < offset; i++) {
211 	    			available[i] = properties[i];
212 	    		}
213 	    		for (int i = 0; i < stocks.length; i++) {
214 	    			available[offset+i] = stocks[i];
215 	    		}
216 		    	
217 	    		setAvailableProperties(available);
218     		} 
219             
220         } catch (Exception e) {
221             handleException(e);
222         } finally {
223         	searchingProperty--;
224         	checkIfIsWorking();
225         }
226     }
227 	
228 	public boolean isBusy() {
229 		return searchingContext!=0 || searchingDevice!=0 || searchingProperty!=0
230 				|| searchingServer!=0 || searchingSubsystem!=0;
231 	}
232 	
233 	private void checkIfIsWorking() {
234 		if (!isBusy())  {
235 			fireQueryFinished("all");
236 		}
237 	}
238 	
239 	/**
240 	 * Returns the selected context.
241 	 * 
242      * @return the selectedContext
243      */
244     public String getSelectedContext() {
245     	return selectedContext;
246     }
247     
248 	/**
249 	 * Selects a context and initiates subsystem query.
250 	 * 
251      * @param selectedContext the selectedContext to set
252      */
253     public synchronized void setSelectedContext(String selectedContext) {
254     	try {
255     		searchingContext++;
256 	    	if ("".equals(selectedContext)) {
257 	    		selectedContext=null;
258 	    	}
259 	    	if (!acceptProperty(this.selectedContext, selectedContext)) {
260 	    		return;
261 	    	}
262 	    	fireQueryStarted("context");
263 	    	String old = this.selectedContext;
264 	    	this.selectedContext = selectedContext;
265 	    	firePropertyChange("selectedContext", old, selectedContext);
266 	    	if (selectedContext != null)
267 	    		performSubsystemQuery();
268 	    	else {
269 	    		setSelectedSubSystem(null);
270 	    		setAvailableSubsystems(null);
271 	    		setSelectedServer(null);
272 	    		setAvailableServers(null);
273 	    		setSelectedDevice(null);
274 	    		setAvailableDevices(null);
275 	    		setSelectedProperty(null);
276 	    		setAvailableProperties(null);
277 	    	}
278     	} catch (Exception e) {
279     		handleException(e);
280     	} finally {
281     		searchingContext--;
282     		fireQueryFinished("context");
283     	}
284     }
285 
286 	/**
287 	 * Returns the selected device.
288 	 * 
289      * @return the selectedDevice
290      */
291     public String getSelectedDevice() {
292     	return selectedDevice;
293     }
294 
295 	/**
296 	 * Selects a device and intiates property names query.
297 	 * 
298      * @param selectedDevice the selectedDevice to set
299      */
300     public synchronized void setSelectedDevice(String selectedDevice) {
301     	try {
302     		searchingDevice++;
303 	    	if ("".equals(selectedDevice)) {
304 	    		selectedDevice=null;
305 	    	}
306 	    	if (!acceptProperty(this.selectedDevice, selectedDevice)) {
307 	    		return;
308 	    	} 
309 	    	fireQueryStarted("device");	 
310 	    	String old = this.selectedDevice;
311 	    	this.selectedDevice = selectedDevice;
312 	    	firePropertyChange("selectedDevice", old, selectedDevice);	
313 	    	if (selectedDevice != null && selectedDevice.contains("*")) {
314 	    		return;
315 	    	}
316 	       	if (this.selectedDevice != null || devicePrecedence) {
317 	    		performPropertyNameQuery(null);
318 	    	} else if (!propertyPrecedence){
319 	    		setAvailableProperties(null);
320 	    	}
321     	} catch (Exception e) {
322     		handleException(e);
323     	} finally {
324     		searchingDevice--;
325     		fireQueryFinished("device");
326     	}
327     }
328 
329 	/**
330 	 * Returns the selected property.
331 	 * 
332      * @return the selectedProperty
333      */
334     public String getSelectedProperty() {
335     	return selectedProperty;
336     }
337 
338 	/**
339 	 * Selects the property and reinitiates the device name query for
340 	 * potential reversed hierarchy.
341 	 * 
342      * @param selectedProperty the selectedProperty to set
343      */
344     public synchronized void setSelectedProperty(String selectedProperty) {
345     	try {
346     		searchingProperty++;
347 	    	if ("".equals(selectedProperty)) {
348 	    		selectedProperty=null;
349 	    	}
350 	    	
351 	    	if (!acceptProperty(this.selectedProperty, selectedProperty)) {
352 	    		return;
353 	    	}
354 	    	fireQueryStarted("property");
355 	    	
356 //	    	if (selectedProperty != null && selectedProperty.endsWith("*")) {
357 //	    		String old = this.selectedProperty;
358 //		    	this.selectedProperty = null;
359 //	    		performPropertyNameQuery(selectedProperty);
360 //	    		firePropertyChange("selectedProperty", old, null);
361 //	    	} else {
362 	    		String old = this.selectedProperty;
363 		    	this.selectedProperty = selectedProperty;
364 		    	if (propertyPrecedence || !devicePrecedence) {
365 		    		performDeviceNameQuery(false);
366 		    	}
367 		    	firePropertyChange("selectedProperty", old, selectedProperty);
368 //	    	}
369     	} catch (Exception e) {
370     		handleException(e);
371     	} finally {
372     		searchingProperty--;
373     		fireQueryFinished("property");
374     	}
375     }
376 
377 	/**
378 	 * Returns the selected server.
379 	 * 
380      * @return the selectedServer
381      */
382     public String getSelectedServer() {
383     	return selectedServer;
384     }
385 
386 	/**
387 	 * Selects the device server and initiates device and property name queryies.
388 	 * 
389      * @param selectedServer the selectedServer to set
390      */
391     public synchronized void setSelectedServer(String selectedServer) {
392     	try {
393     		searchingServer++;
394 	    	if ("".equals(selectedServer)) {
395 	    		selectedServer=null;
396 	    	}
397 	
398 	    	if (!acceptProperty(this.selectedServer, selectedServer)) {
399 	    		return;
400 	    	}
401 	    	fireQueryStarted("server");
402 	    	String old = this.selectedServer;
403 	    	this.selectedServer = selectedServer;
404 	    	propertyPrecedence = false;
405 	    	devicePrecedence = false;
406 	    	firePropertyChange("selectedServer", old, selectedServer);
407 	    	    	
408 	    	setSelectedProperty(null);
409 			setSelectedDevice(null);
410 	
411 	    	setAvailableDevices(null);
412 	    	performDeviceNameQuery(true);
413 	    	performPropertyNameQuery(null);
414     	} catch (Exception e) {
415     		handleException(e);
416     	} finally {
417     		searchingServer--;
418     		fireQueryFinished("server");
419     	}
420     }
421     
422 	/**
423 	 * Returns the selected protocol.
424 	 * 
425      * @return the selectedProtocol
426      */
427     public String getSelectedProtocol() {
428     	return selectedProtocol;
429     }
430     
431     private boolean acceptProperty(String oldP, String newP) {
432     	if (oldP == null && newP == null) return false;
433     	else if (oldP != null && newP != null &&
434     			oldP.equals(newP)) return false;
435     	return true;
436     }
437 
438 	/**
439 	 * Selects a device protocol and initiates qontext search.
440 	 * 
441      * @param selectedProtocol the selectedProtocol to set
442      */
443     public synchronized void setSelectedProtocol(String selectedProtocol) {
444     	try {
445 	    	if ("".equals(selectedProtocol)) {
446 	    		selectedProtocol=null;
447 	    	}
448 
449 	    	if (!acceptProperty(this.selectedProtocol, selectedProtocol)) {
450 	    		return;
451 	    	}
452 	    	
453 	    	fireQueryStarted("protocol");
454 	    	String old = this.selectedProtocol;
455 	    	this.selectedProtocol = selectedProtocol;
456 	
457 	    	firePropertyChange("selectedProtocol", old, selectedProtocol);
458 	    	if (selectedProtocol == null) {
459 	    		setSelectedContext(null);
460 	    		setAvailableContexts(null);
461 	    		setSelectedServer(null);
462 	    		setAvailableServers(null);
463 	    		setSelectedDevice(null);
464 	    		setAvailableDevices(null);
465 	    		setSelectedProperty(null);
466 	    		setAvailableProperties(null);
467 	    	} else {
468 	    		performContextQuery();
469 	    	}
470 
471     	} catch (Exception e) {
472     		handleException(e);
473     	} finally {
474     		fireQueryFinished("protocol");
475     	}
476 
477     	
478     }
479 
480 	/**
481 	 * Returns all available contexts loaded from remote server.
482 	 * 
483      * @return the availableContexts
484      */
485     public String[] getAvailableContexts() {
486     	return availableContexts;
487     }
488 
489 	/**
490 	 * Returns all available devices loaded from remote server.
491 	 * 
492      * @return the availableDevices
493      */
494     public String[] getAvailableDevices() {
495     	return availableDevices;
496     }
497 
498 	/**
499 	 * Returns all available properties loaded from remote server.
500 	 * 
501      * @return the availableProperties
502      */
503     public String[] getAvailableProperties() {
504     	return availableProperties;
505     }
506 
507 	/**
508 	 * Returns all available servers loaded from remote server.
509      * @return the availableServers
510      */
511     public String[] getAvailableServers() {
512     	return availableServers;
513     }
514     
515     protected void firePropertyChange(String name, Object oldValue, Object newValue) {
516     	if (oldValue == null && newValue == null) return;
517     	propertyChangeSupport.firePropertyChange(name, oldValue, newValue);
518     }
519     
520     /**
521      * Adds a PropertyChangeListener and assigns it to listen to a specific property.
522      * 
523      * @param name the name of the property
524      * @param l the listener to be added
525      */
526     public void addPropertyChangeListener(String name, PropertyChangeListener l) {
527     	propertyChangeSupport.addPropertyChangeListener(name, l);
528     }
529     
530     /**
531      * Removes a PropertyChangeListener from listening a specific property.
532      * 
533      * @param name the name of the property that the listener has been listening to
534      * @param l the listener to be removed
535      */
536     public void removePropertyChangeListener(String name, PropertyChangeListener l) {
537     	propertyChangeSupport.removePropertyChangeListener(name, l);
538     }
539     
540     /**
541      * Adds a PropertyChangeListener for all properties.
542      * 
543      * @param l listener to be added
544      */
545     public void addPropertyChangeListener(PropertyChangeListener l) {
546     	propertyChangeSupport.addPropertyChangeListener(l);
547     }
548     
549     /**
550      * Removes a PropertyChangeListener.
551      * 
552      * @param l listener to be removed
553      */
554     public void removePropertyChangeListener(PropertyChangeListener l) {
555     	propertyChangeSupport.removePropertyChangeListener(l);
556     }
557 
558     private String[] addDefaultContext(String[] contexts) {
559     	String[] availableContextsTemp = new String[contexts.length + 1];
560     	availableContextsTemp[0] = "DEFAULT";
561     	for (int i = 0; i < contexts.length; i++) {
562     		availableContextsTemp[i+1] = contexts[i];
563     	}
564     	return availableContextsTemp;
565     }
566     
567     @SuppressWarnings("unchecked")
568 	private synchronized void setAvailableContexts(String[] availableContexts) {
569     	if (this.availableContexts == null && availableContexts == null) return;
570     	String[] old = this.availableContexts;
571     	if (availableContexts != null) 
572     		Arrays.sort(availableContexts, comparator);
573     	else 
574     		availableContexts = new String[0];
575     	//add default context
576     	String[] availableContextsTemp = addDefaultContext(availableContexts);
577     	if (Arrays.equals(this.availableContexts, availableContextsTemp)) return;    	
578     	this.availableContexts = availableContextsTemp;
579     	firePropertyChange("availableContexts", old, availableContexts);
580 	    	if (this.availableContexts != null) {
581 		    	for (String p: this.availableContexts) {
582 		    		if (p.equals(selectedContext)) {
583 		    			performSubsystemQuery();
584 		    			return;
585 		    		}
586 		    	}
587 		    	if (this.availableContexts.length > 0) {
588 		    		setSelectedContext(this.availableContexts[0]);
589 		    	} else {
590 		    		setSelectedContext(null);
591 		    		setSelectedSubSystem(null);
592 		    		setSelectedServer(null);
593 			    	setSelectedDevice(null);
594 			    	setSelectedProperty(null);
595 		    	}
596 	    	} 
597     }
598 
599     private synchronized void setAvailableDevices(String[] availableDevices) {
600     	if (this.availableDevices == null && availableDevices == null) return;
601     	String[] old = this.availableDevices;
602     	
603     	if (Arrays.equals(this.availableDevices, availableDevices)) return;
604     	
605     	this.availableDevices = availableDevices;
606 
607     	firePropertyChange("availableDevices", old, availableDevices);
608 	    	if (this.availableDevices != null) {
609 				for (String p: this.availableDevices) {
610 		    		if (p.equals(selectedDevice)) {
611 		    			performPropertyNameQuery(null);
612 		    			return;
613 		    		}
614 		    	}
615 				
616 				if (!propertyPrecedence) {
617 					setSelectedDevice(null);
618 		    		setSelectedProperty(null);
619 				} else {
620 					performPropertyNameQuery(null);
621 				}
622 				
623 				if (!propertyPrecedence && !devicePrecedence) {
624 					performPropertyNameQuery(null);
625 				}
626 							
627 				for (String p: this.availableDevices) {
628 		    		if (p.equals(selectedDevice)) {
629 		    			return;
630 		    		}
631 		    	}
632 				if (this.availableDevices.length > 0) {
633 			 		setSelectedDevice(this.availableDevices[0]);
634 		    	} else {
635 		    		setSelectedDevice(null);
636 		    	}
637 	    	}
638     }
639 
640     @SuppressWarnings("unchecked")
641 	private synchronized void setAvailableProperties(String[] availableProperties) {
642     	if (this.availableProperties == null && availableProperties == null) return;
643     	String[] old = this.availableProperties;
644     	if (availableProperties != null) 
645     		Arrays.sort(availableProperties, comparator);
646     	if (Arrays.equals(this.availableProperties, availableProperties)) return;
647     	this.availableProperties = availableProperties;
648     	
649     	firePropertyChange("availableSubsystems", old, availableSubsystems);
650 	    	if (this.availableProperties != null) {
651 	    		for (String p: this.availableProperties) {
652 		    		if (p.equals(selectedProperty)) {
653 		    			if (propertyPrecedence) {
654 		    	    		performDeviceNameQuery(false);
655 		    	    	} 
656 		    			return;
657 		    		}
658 		    	}
659 	    		if (this.availableProperties.length > 0) {
660 			 		setSelectedProperty(this.availableProperties[0]);
661 		    	} else {
662 		    		setSelectedProperty(null);
663 		    	}
664 	    	}
665     }
666 
667     @SuppressWarnings("unchecked")
668 	private synchronized void setAvailableServers(String[] availableServers) {
669     	if (this.availableServers == null && availableServers == null)return;
670     	String[] old = this.availableServers;
671     	if (availableServers != null)
672     		Arrays.sort(availableServers, comparator);
673     	if (Arrays.equals(this.availableServers, availableServers)) return;
674     	
675     	this.availableServers = availableServers;
676     	propertyPrecedence = false;
677         devicePrecedence = false;
678     	firePropertyChange("availableServers", old, availableServers);
679 	    	if (this.availableServers != null) {
680 		    	for (String p: this.availableServers) {
681 		    		if (p.equals(selectedServer)) {
682 		    			performDeviceNameQuery(true);
683 		    			return;
684 		    		}
685 		    	}
686 		    	if (this.availableServers.length > 0) {
687 		    		setSelectedServer(this.availableServers[0]);
688 		    	} else {
689 		    		setSelectedServer(null);
690 		    		setSelectedDevice(null);
691 			    	setSelectedProperty(null);
692 		    	}
693 		    	
694 	    	}
695     }  
696     
697     private String[] filterSubsystems(String[] subs) {
698     	
699     	ArrayList<String> availableSubsystemsTemp = new ArrayList<String>();
700     	availableSubsystemsTemp.add("ALL");
701     	for (String sub : subs) {
702     		if (sub == null || sub.trim().length()==0 || "TEST".equals(sub)) continue;
703     		availableSubsystemsTemp.add(sub);
704     	}
705     	availableSubsystemsTemp.add("TEST");
706     	return availableSubsystemsTemp.toArray(new String[availableSubsystemsTemp.size()]);
707     }
708     
709     /**
710      * Returns all available subsystems loaded from the remote server.
711      * 
712      * @return available subsystems
713      */
714     public String[] getAvailableSubsystems() {
715     	return availableSubsystems;
716     }
717     
718     @SuppressWarnings("unchecked")
719 	private synchronized void setAvailableSubsystems(String[] availableSubsystems) {
720     	if (this.availableSubsystems == null && availableSubsystems == null) return;
721     	String[] old = this.availableSubsystems;
722     	if (availableSubsystems != null) 
723     		Arrays.sort(availableSubsystems, comparator);
724     	else 
725     		availableSubsystems = new String[0];
726     	//add default context
727     	String[] availableSubsystemsTemp = filterSubsystems(availableSubsystems);
728     	if (Arrays.equals(this.availableSubsystems, availableSubsystems)) return;    	
729     	this.availableSubsystems = availableSubsystemsTemp;
730     	firePropertyChange("availableSubsystems", old, availableSubsystems);
731 	    	if (this.availableSubsystems != null) {
732 		    	for (String p: this.availableSubsystems) {
733 		    		if (p.equals(selectedSubSystem)) {
734 		    			performServerQuery();
735 		    			return;
736 		    		}
737 		    	}
738 		    	if (this.availableSubsystems.length > 0) {
739 		    		setSelectedSubSystem(this.availableSubsystems[0]);
740 		    	} else {
741 		    		setSelectedSubSystem(null);
742 		    		setSelectedServer(null);
743 			    	setSelectedDevice(null);
744 			    	setSelectedProperty(null);
745 		    	}
746 		    	
747 	    	} 
748     }   
749 
750 	/**
751 	 * Returns all available protocols.
752 	 * 
753      * @return the availableProtcols
754      */
755     public String[] getAvailableProtcols() {
756     	return availableProtcols;
757     }
758     
759     /**
760      * Adds a QueryListener which receives notifications when query is started or 
761      * finished.
762      * 
763      * @param l listener to be added
764      */
765     public void addQueryListener(QueryListener l) {
766     	queryListeners.add(l);
767     }
768     
769     /**
770      * Removes a QueryListener.
771      * 
772      * @param l listener to be removed
773      */
774     public void removeQueryListener(QueryListener l) {
775     	queryListeners.remove(l);
776     }
777     
778     protected synchronized void fireQueryStarted(String process) {
779     	queries++;
780     	QueryEvent e = new QueryEvent(this, process);
781     	QueryListener[] listeners = (QueryListener[]) queryListeners.toArray();
782     	for (QueryListener lis : listeners) {
783     		try {
784     			lis.queryStarted(e);
785     		} catch (Exception e1) {
786     			handleException(e1);
787     		}
788     	}
789     }
790     
791     protected synchronized void fireQueryFinished(String process) {
792     	if (--queries>0) {
793     		return;
794     	}
795     	if (queries < 0) queries = 0;
796     	QueryEvent e = new QueryEvent(this, process);
797     	QueryListener[] listeners = (QueryListener[]) queryListeners.toArray();
798     	for (QueryListener lis : listeners) {
799     		try {
800     			lis.queryFinished(e);
801     		} catch (Exception e1) {
802     			handleException(e1);
803     		}
804     	}
805     }
806     
807     /**
808      * Returns the remote name constructed from the selected parameters.
809      * @return the remote name
810      */
811     public String getRemoteName() {
812     	return (selectedProtocol != null ? selectedProtocol : "") + "/" + 
813     		    (selectedContext != null ? selectedContext : "") + "/" + 
814     		    (selectedServer != null ? selectedServer : "") + "/" +
815     		    (selectedDevice != null ? selectedDevice : "") + "/" +
816     		    (selectedProperty != null ? selectedProperty : "");
817     }
818     
819     void resetSelector() {
820     	availableContexts = null;
821     	availableServers = null;
822     	availableDevices = null;
823     	availableProperties = null;
824     	selectedProtocol = null;
825     	selectedContext = null;
826     	selectedServer = null;
827     	selectedDevice = null;
828     	selectedProperty = null;
829     }
830 
831 	/**
832 	 * Returns a flag if stock properties should also be loaded at the same time
833 	 * when properties are loaded.
834 	 * 
835      * @return the showStockProperties
836      */
837     public boolean isShowStockProperties() {
838     	return showStockProperties;
839     }
840 
841 	/**
842 	 * Sets the stock properties flag. If true stock properties will be 
843 	 * loaded together with normal properties.
844 	 * 
845      * @param showStockProperties the showStockProperties to set
846      */
847     public synchronized void setShowStockProperties(boolean showStockProperties) {
848     	try {
849 	    	if (this.showStockProperties == showStockProperties) return;
850 	    	
851 	    	fireQueryStarted("stockProperty");
852 	    	this.showStockProperties = showStockProperties;
853 	    	firePropertyChange("showStockProperties", !showStockProperties, showStockProperties);
854 			performPropertyNameQuery(null);
855 	    	
856     	} catch (Exception e) {
857     		handleException(e);
858     	} finally {
859     		fireQueryFinished("stockProperty");
860     	}
861     }
862 
863 	/**
864 	 * Returns the selected subsystem.
865 	 * 
866      * @return the selectedSubSystem
867      */
868     public String getSelectedSubSystem() {
869     	return selectedSubSystem;
870     }
871 
872 	/**
873 	 * Selects the subsystem and initiates server query.
874 	 * 
875      * @param selectedSubSystem the selectedSubSystem to set
876      */
877     public synchronized void setSelectedSubSystem(String selectedSubSystem) {
878     	try {
879     		searchingSubsystem++;
880 //	    	if ("".equals(selectedSubSystem) || selectedSubSystem == null) {
881 //	    		selectedSubSystem="ALL";
882 //	    	}
883 	
884 	    	if (!acceptProperty(this.selectedSubSystem, selectedSubSystem)) {
885 	    		return;
886 	    	}
887 	    	fireQueryStarted("subSystem");
888 	    	String old = this.selectedSubSystem;
889 	    	this.selectedSubSystem = selectedSubSystem;
890 	    	firePropertyChange("selectedSubSystem", old, selectedSubSystem);
891 	    	if (selectedSubSystem != null)
892 	    		performServerQuery();
893 	    	else {
894 	    		setSelectedServer(null);
895 	    		setAvailableServers(null);
896 	    		setSelectedDevice(null);
897 	    		setAvailableDevices(null);
898 	    		setSelectedProperty(null);
899 	    		setAvailableProperties(null);
900 	    	}
901 	    		
902     	} catch (Exception e) {
903     		handleException(e);
904     	} finally {
905     		searchingSubsystem--;
906     		fireQueryFinished("subSystem");
907     	}
908     }
909     
910     /**
911      * Sets the access rate.
912      * 
913      * @param value new access rate in millis
914      */
915     public void setAccessRate(int value) {
916     	int oldValue = accessRate;
917     	this.accessRate = value;
918     	firePropertyChange("accessRate", oldValue, this.accessRate);
919     }
920     
921     /**
922      * Returns the access rate.
923      * 
924      * @return the access rate
925      */
926     public int getAccessRate() {
927     	return this.accessRate;
928     }
929     
930     /**
931      * Sets the access mode.
932      * 
933      * @param mode new access mode
934      */
935     public void setAccessMode(AccessMode mode) {
936     	AccessMode oldValue = accessMode;
937     	this.accessMode = mode;
938     	firePropertyChange("accessMode", oldValue, this.accessMode);
939     }
940     
941     /**
942      * Returns selected access mode.
943      * 
944      * @return the access mode
945      */
946     public AccessMode getAccessMode() {
947     	return this.accessMode;
948     }
949        
950     
951     /**
952      * Adds an ExceptionListener which receives notifications of all exceptions
953      * that occured while queries were performed.
954      * 
955      * @param l listener to be added
956      */
957     public void addExceptionListener(ExceptionListener l) {
958     	exceptionListeners.add(l);
959     }
960     
961     /**
962      * Removes an ExceptionListener.
963      * 
964      * @param l listener to be removed
965      */
966     public void removeExceptionListener(ExceptionListener l) {
967     	exceptionListeners.remove(l);
968     }
969     
970     private void handleException(Throwable e) {
971     	ExceptionEvent event = new ExceptionEvent(this, e);
972     	ExceptionListener[] listeners = (ExceptionListener[]) exceptionListeners.toArray();
973     	for (ExceptionListener lis : listeners) {
974     		try {
975     			lis.exceptionReceived(event);
976     		} catch (Exception e1) {
977     			handleException(e1);
978     		}
979     	}
980     }
981     
982     
983 	
984 }
985 
986 
987 /* __oOo__ */