View Javadoc
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.jca;
6   
7   import gov.aps.jca.CAException;
8   import gov.aps.jca.Context;
9   import gov.aps.jca.JCALibrary;
10  import gov.aps.jca.Monitor;
11  import java.util.logging.Level;
12  import java.util.logging.Logger;
13  import org.epics.pvmanager.ChannelHandler;
14  import org.epics.pvmanager.DataSource;
15  import org.epics.pvmanager.vtype.DataTypeSupport;
16  import com.cosylab.epics.caj.CAJContext;
17  import gov.aps.jca.jni.JNIContext;
18  import java.lang.reflect.InvocationTargetException;
19  import java.lang.reflect.Method;
20  import java.security.AccessController;
21  import java.security.PrivilegedAction;
22  import java.util.concurrent.ExecutorService;
23  import java.util.concurrent.Executors;
24  import static org.epics.pvmanager.util.Executors.namedPool;
25  
26  /**
27   * A data source that uses jca.
28   * <p>
29   * Type support can be configured by passing a custom {@link JCATypeSupport}
30   * to the constructor.
31   * 
32   * @author carcassi
33   */
34  public class JCADataSource extends DataSource {
35  
36      static {
37          // Install type support for the types it generates.
38          DataTypeSupport.install();
39      }
40  
41      private static final Logger log = Logger.getLogger(JCADataSource.class.getName());
42  
43      private final Context ctxt;
44      private final int monitorMask;
45      private final boolean varArraySupported;
46      private final boolean dbePropertySupported;
47      private final JCATypeSupport typeSupport;
48      private final boolean rtypValueOnly;
49      private final boolean honorZeroPrecision;
50  
51      /**
52       * Creates a new data source using pure Java implementation and all the
53       * defaults described in {@link JCADataSourceBuilder}.
54       */
55      public JCADataSource() {
56          this(new JCADataSourceBuilder());
57      }
58      
59      /**
60       * Creates a new data source using the given context. The context will
61       * never be closed.
62       * 
63       * @param jcaContext the context to be used
64       * @param monitorMask Monitor.VALUE, ...
65       * @deprecated use {@link JCADataSourceBuilder}
66       */
67      @Deprecated
68      public JCADataSource(Context jcaContext, int monitorMask) {
69          this(new JCADataSourceBuilder().jcaContext(jcaContext).monitorMask(monitorMask));
70      }
71  
72      /**
73       * Creates a new data source using the className to create the context.
74       *
75       * @param className JCALibrary.CHANNEL_ACCESS_JAVA, JCALibrary.JNI_THREAD_SAFE, ...
76       * @param monitorMask Monitor.VALUE, ...
77       * @deprecated use {@link JCADataSourceBuilder}
78       */
79      @Deprecated
80      public JCADataSource(String className, int monitorMask) {
81          this(new JCADataSourceBuilder().jcaContextClass(className).monitorMask(monitorMask));
82      }
83      
84      /**
85       * Creates a new data source using the given context. The context will
86       * never be closed. The type mapping con be configured with a custom
87       * type support.
88       * 
89       * @param jcaContext the context to be used
90       * @param monitorMask Monitor.VALUE, ...
91       * @param typeSupport type support to be used
92       * @deprecated use {@link JCADataSourceBuilder}
93       */
94      @Deprecated
95      public JCADataSource(Context jcaContext, int monitorMask, JCATypeSupport typeSupport) {
96          this(new JCADataSourceBuilder().jcaContext(jcaContext).monitorMask(monitorMask)
97                  .typeSupport(typeSupport));
98      }
99      
100     /**
101      * Creates a new data source using the given context. The context will
102      * never be closed. The type mapping con be configured with a custom
103      * type support.
104      * 
105      * @param jcaContext the context to be used
106      * @param monitorMask Monitor.VALUE, ...
107      * @param typeSupport type support to be used
108      * @param dbePropertySupported whether metadata monitors should be used
109      * @param varArraySupported true if var array should be used 
110      * @deprecated use {@link JCADataSourceBuilder}
111      */
112     @Deprecated
113     public JCADataSource(Context jcaContext, int monitorMask, JCATypeSupport typeSupport, boolean dbePropertySupported, boolean varArraySupported) {
114         this(new JCADataSourceBuilder().jcaContext(jcaContext).monitorMask(monitorMask)
115                 .typeSupport(typeSupport).dbePropertySupported(dbePropertySupported)
116                 .varArraySupported(varArraySupported));
117     }
118     
119     protected JCADataSource(JCADataSourceBuilder builder) {
120         super(true);
121         // Some properties are not pre-initialized to the default,
122         // so if they were not set, we should initialize them.
123         
124         // Default JCA context is pure Java
125         if (builder.jcaContext == null) {
126             ctxt = JCADataSourceBuilder.createContext(JCALibrary.CHANNEL_ACCESS_JAVA);
127         } else {
128             ctxt = builder.jcaContext;
129         }
130 
131         try {
132             if (ctxt instanceof CAJContext) {
133                 ((CAJContext) ctxt).setDoNotShareChannels(true);
134             }
135         } catch (Throwable t) {
136             log.log(Level.WARNING, "Couldn't change CAJContext to doNotShareChannels: this may cause some rare notification problems.", t);
137         }
138         
139         // Default type support are the VTypes
140         if (builder.typeSupport == null) {
141             typeSupport = new JCATypeSupport(new JCAVTypeAdapterSet());
142         } else {
143             typeSupport = builder.typeSupport;
144         }
145 
146         // Default support for var array needs to be detected
147         if (builder.varArraySupported == null) {
148             varArraySupported = JCADataSourceBuilder.isVarArraySupported(ctxt);
149         } else {
150             varArraySupported = builder.varArraySupported;
151         }
152         
153         monitorMask = builder.monitorMask;
154         dbePropertySupported = builder.dbePropertySupported;
155         rtypValueOnly = builder.rtypValueOnly;
156         honorZeroPrecision = builder.honorZeroPrecision;
157         
158         if (useContextSwitchForAccessRightCallback()) {
159             contextSwitch = Executors.newSingleThreadExecutor(namedPool("PVMgr JCA Workaround "));
160         } else {
161             contextSwitch = null;
162         }
163     }
164 
165     @Override
166     public void close() {
167         super.close();
168         ctxt.dispose();
169     }
170 
171     /**
172      * The context used by the data source.
173      * 
174      * @return the data source context
175      */
176     public Context getContext() {
177         return ctxt;
178     }
179 
180     /**
181      * The monitor mask used for this data source.
182      * 
183      * @return the monitor mask
184      */
185     public int getMonitorMask() {
186         return monitorMask;
187     }
188 
189     /**
190      * Whether the metadata monitor should be established.
191      * 
192      * @return true if using metadata monitors
193      */
194     public boolean isDbePropertySupported() {
195         return dbePropertySupported;
196     }
197 
198     @Override
199     protected ChannelHandler createChannel(String channelName) {
200         return new JCAChannelHandler(channelName, this);
201     }
202 
203     JCATypeSupport getTypeSupport() {
204         return typeSupport;
205     }
206     
207     /**
208      * True whether the context can use variable arrays (all
209      * array monitor request will have an element count of 0).
210      * 
211      * @return true if variable size arrays are supported
212      */
213     public boolean isVarArraySupported() {
214         return varArraySupported;
215     }
216 
217     /**
218      * True if should only ask value for RTYP fields.
219      * 
220      * @return true if asking for value only
221      */
222     public boolean isRtypValueOnly() {
223         return rtypValueOnly;
224     }
225 
226     /**
227      * True if zero precision should be honored, or disregarded.
228      * 
229      * @return true if zero precision setting is honored
230      */
231     public boolean isHonorZeroPrecision() {
232         return honorZeroPrecision;
233     }
234     
235     /**
236      * Determines whether the context supports variable arrays
237      * or not.
238      * 
239      * @param context a JCA Context
240      * @return true if supports variable sized arrays
241      */
242     @Deprecated
243     public static boolean isVarArraySupported(Context context) {
244         return JCADataSourceBuilder.isVarArraySupported(context);
245     }
246     
247     final boolean useContextSwitchForAccessRightCallback() {
248         if (ctxt instanceof JNIContext) {
249             return true;
250         }
251         return false;
252     }
253     
254     ExecutorService getContextSwitch() {
255         return contextSwitch;
256     }
257     
258     private final ExecutorService contextSwitch;
259     
260 }