1 /**
2 * Copyright (C) 2010-14 pvmanager developers. See COPYRIGHT.TXT
3 * All rights reserved. Use is subject to license terms. See LICENSE.TXT
4 */
5 package org.epics.pvmanager;
6
7 import java.util.concurrent.Executor;
8 import java.util.concurrent.Executors;
9 import java.util.concurrent.ScheduledExecutorService;
10 import org.epics.pvmanager.expression.DesiredRateExpression;
11 import org.epics.pvmanager.expression.DesiredRateReadWriteExpression;
12 import org.epics.pvmanager.expression.SourceRateExpression;
13 import org.epics.pvmanager.expression.SourceRateReadWriteExpression;
14 import org.epics.pvmanager.expression.WriteExpression;
15
16 /**
17 * Entry point for the library, manages the defaults and allows to create
18 * {@link PVReader}, {@link PVWriter} and {@link PV } from an read or write expression.
19 * <p>
20 * <b>NotificationExecutor</b> - This is used for all notifications.
21 * By default this uses {@link org.epics.pvmanager.util.Executors#localThread()} so that
22 * the notification are done on whatever current thread needs to notify.
23 * This means that new read notifications are run on threads managed by
24 * the ReadScannerExecutorService, write notifications are run on threads
25 * managed by the DataSource and exceptions notification are run on the thread
26 * where the exception is done. This can be changed to make all notifications
27 * routed to single threaded sub-systems, such as UI environments like SWING,
28 * SWT or similar. This can be changed on a PV by PV basis.
29 * <p>
30 * <b>AsynchWriteExecutor</b> - This is used for asynchronous writes, to return
31 * right away, and for running timeouts on each write.
32 * By default this uses the internal PVManager work pool. The work
33 * submitted here is the calculation of the corresponding {@link WriteExpression}
34 * and submission to the {@link DataSource}. The DataSource itself typically
35 * has asynchronous work, which is executed in the DataSource specific threads.
36 * Changing this to {@link org.epics.pvmanager.util.Executors#localThread()} will make that preparation
37 * task on the thread that calls {@link PVWriter#write(java.lang.Object) } but
38 * it will not transform the call in a synchronous call.
39 * <p>
40 * <b>ReadScannerExecutorService</b> - This is used to run the periodic
41 * scan for new values. By default this uses the internal PVManager work pool. The work
42 * submitted here is the calculation of the corresponding {@link DesiredRateExpression}
43 * and submission to the NotificationExecutor.
44 *
45 * @author carcassi
46 */
47 public class PVManager {
48
49 private static volatile Executor defaultNotificationExecutor = org.epics.pvmanager.util.Executors.localThread();
50 private static volatile DataSource defaultDataSource = null;
51 private static final ScheduledExecutorService workerPool = Executors.newScheduledThreadPool(Math.max(1, Runtime.getRuntime().availableProcessors() - 1),
52 org.epics.pvmanager.util.Executors.namedPool("PVMgr Worker "));
53 private static ScheduledExecutorService readScannerExecutorService = workerPool;
54 private static ScheduledExecutorService asyncWriteExecutor = workerPool;
55
56 /**
57 * Changes the default executor on which all notifications are going to be posted.
58 *
59 * @param notificationExecutor the new notification executor
60 */
61 public static void setDefaultNotificationExecutor(Executor notificationExecutor) {
62 defaultNotificationExecutor = notificationExecutor;
63 }
64
65 /**
66 * Returns the current default executor that will execute all notifications.
67 *
68 * @return the default executor
69 */
70 public static Executor getDefaultNotificationExecutor() {
71 return defaultNotificationExecutor;
72 }
73
74 /**
75 * Changes the default source for data.
76 *
77 * @param dataSource the data source
78 */
79 public static void setDefaultDataSource(DataSource dataSource) {
80 PVManager.defaultDataSource = dataSource;
81 }
82
83 /**
84 * Returns the current default data source.
85 *
86 * @return a data source or null if it was not set
87 */
88 public static DataSource getDefaultDataSource() {
89 return defaultDataSource;
90 }
91
92 /**
93 * Reads the given expression, and returns an object to configure the parameters
94 * for the read. At each notification it will return the latest value,
95 * even if more had been received from the last notification.
96 *
97 * @param <T> type of the read payload
98 * @param pvExpression the expression to read
99 * @return the read configuration
100 */
101 public static <T> PVReaderConfiguration<T> read(SourceRateExpression<T> pvExpression) {
102 return new PVReaderConfiguration<T>(ExpressionLanguage.latestValueOf(pvExpression));
103 }
104
105 /**
106 * Reads the given expression, and returns an object to configure the parameters
107 * for the read.
108 *
109 * @param <T> type of the read payload
110 * @param pvExpression the expression to read
111 * @return the read configuration
112 */
113 public static <T> PVReaderConfiguration<T> read(DesiredRateExpression<T> pvExpression) {
114 return new PVReaderConfiguration<T>(pvExpression);
115 }
116
117 /**
118 * Writes the given expression, and returns an object to configure the parameters
119 * for the write.
120 *
121 * @param <T> type of the write payload
122 * @param writeExpression the expression to write
123 * @return the write configuration
124 */
125 public static <T> PVWriterConfiguration<T> write(WriteExpression<T> writeExpression) {
126 return new PVWriterConfiguration<T>(writeExpression);
127 }
128
129 /**
130 * Both reads and writes the given expression, and returns an object to configure the parameters
131 * for the both read and write. It's similar to use both {@link #read(org.epics.pvmanager.expression.SourceRateExpression) }
132 * and {@link #write(org.epics.pvmanager.expression.WriteExpression) } at the same time.
133 *
134 * @param <R> type of the read payload
135 * @param <W> type of the write payload
136 * @param readWriteExpression the expression to read and write
137 * @return the read and write configuration
138 */
139 public static <R, W> PVConfiguration<R, W> readAndWrite(SourceRateReadWriteExpression<R, W> readWriteExpression) {
140 return readAndWrite(ExpressionLanguage.latestValueOf(readWriteExpression));
141 }
142
143 /**
144 * Both reads and writes the given expression, and returns an object to configure the parameters
145 * for the both read and write. It's similar to use both {@link #read(org.epics.pvmanager.expression.SourceRateExpression) }
146 * and {@link #write(org.epics.pvmanager.expression.WriteExpression) } at the same time.
147 *
148 * @param <R> type of the read payload
149 * @param <W> type of the write payload
150 * @param readWriteExpression the expression to read and write
151 * @return the read and write configuration
152 */
153 public static <R, W> PVConfiguration<R, W> readAndWrite(DesiredRateReadWriteExpression<R, W> readWriteExpression) {
154 return new PVConfiguration<R, W>(readWriteExpression);
155 }
156
157 /**
158 * Returns the current executor on which the asynchronous calls are executed.
159 *
160 * @return the current executor
161 */
162 public static ScheduledExecutorService getAsyncWriteExecutor() {
163 return asyncWriteExecutor;
164 }
165
166 /**
167 * Changes the executor used for the asynchronous write calls.
168 *
169 * @param asyncWriteExecutor the new executor
170 */
171 public static void setAsyncWriteExecutor(ScheduledExecutorService asyncWriteExecutor) {
172 PVManager.asyncWriteExecutor = asyncWriteExecutor;
173 }
174
175 /**
176 * Returns the executor service used to schedule and run the
177 * periodic reading scan for new values.
178 *
179 * @return the service for the read operations
180 */
181 public static ScheduledExecutorService getReadScannerExecutorService() {
182 return readScannerExecutorService;
183 }
184
185 /**
186 * Changes the executor service to use for executing the periodic read
187 * scan.
188 *
189 * @param readScannerExecutorService the new service for the read operations
190 */
191 public static void setReadScannerExecutorService(ScheduledExecutorService readScannerExecutorService) {
192 PVManager.readScannerExecutorService = readScannerExecutorService;
193 }
194
195 }