Imported Upstream version 1.0.0
[platform/upstream/iotivity.git] / service / resource-encapsulation / android / service / src / main / java / org / iotivity / service / server / RcsResourceObject.java
1 /******************************************************************
2  *
3  * Copyright 2015 Samsung Electronics All Rights Reserved.
4  *
5  *
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  ******************************************************************/
20 /**
21  * @file   RCSResourceObject.java
22  *
23  *  This file contains the resource object APIs provided to the developers.
24  *        RCSResourceObject is a part of the server builder module.
25  *
26  */
27
28 package org.iotivity.service.server;
29
30 import java.lang.ref.WeakReference;
31
32 import org.iotivity.service.RcsDestroyedObjectException;
33 import org.iotivity.service.RcsException;
34 import org.iotivity.service.RcsIllegalStateException;
35 import org.iotivity.service.RcsObject;
36 import org.iotivity.service.RcsPlatformException;
37 import org.iotivity.service.RcsResourceAttributes;
38 import org.iotivity.service.RcsValue;
39
40 /**
41  * RCSResourceObject represents a resource. It handles any requests from clients
42  * automatically with attributes.
43  * <p>
44  * It also provides an auto notification mechanism that notifies to the
45  * observers. Requests are handled automatically by defaultAction of
46  * {@link RcsGetResponse} and {@link RcsSetResponse}. You can override them and
47  * send your own response with {@link GetRequestHandler} and
48  * {@link SetRequestHandler}.
49  * <p>
50  * For simple resources, they are simply required to notify whenever attributes
51  * are changed by a set request. In this case, add an
52  * {@link OnAttributeUpdatedListener} with a key interested in instead of
53  * overriding {@link SetRequestHandler}.
54  *
55  * @see Builder
56  */
57 public final class RcsResourceObject extends RcsObject {
58     /**
59      * This is a builder to create resource with properties and attributes.
60      *
61      * The resource will be observable and discoverable by default, to make them
62      * disable
63      * set these properties explicitly with setDiscoverable and setObservable.
64      *
65      */
66     public static class Builder {
67         private final String          mUri;
68         private final String          mType;
69         private final String          mInterface;
70         private boolean               mIsObservable    = true;
71         private boolean               mIsDiscovervable = true;
72         private RcsResourceAttributes mAttributes;
73
74         /**
75          * Constructs a Builder.
76          *
77          * @param uri
78          *            resource uri
79          * @param resourceType
80          *            resource type
81          * @param resourceInterface
82          *            resource interface
83          *
84          * @throws NullPointerException
85          *             if any parameter is null
86          */
87         public Builder(String uri, String resourceType,
88                 String resourceInterface) {
89             if (uri == null) {
90                 throw new NullPointerException("uri is null.");
91             }
92             if (resourceType == null) {
93                 throw new NullPointerException("resourceType is null.");
94             }
95             if (resourceInterface == null) {
96                 throw new NullPointerException("resourceInterface is null.");
97             }
98
99             mUri = uri;
100             mType = resourceType;
101             mInterface = resourceInterface;
102         }
103
104         /**
105          * Sets whether the resource is discoverable.
106          *
107          * @param isDiscoverable
108          *            whether to be discoverable or not
109          *
110          */
111         public Builder setDiscoverable(boolean isDiscoverable) {
112             mIsDiscovervable = isDiscoverable;
113             return this;
114         }
115
116         /**
117          * Sets the observable(OC_OBSERVABLE) property of the resource.
118          *
119          * @param isObservable
120          *            whether to be observable or not
121          *
122          */
123         public Builder setObservable(boolean isObservable) {
124             mIsObservable = isObservable;
125             return this;
126         }
127
128         /**
129          * Sets attributes foe the resource.
130          *
131          */
132         public Builder setAttributes(RcsResourceAttributes attributes) {
133             mAttributes = attributes;
134             return this;
135         }
136
137         /**
138          * Register a resource and returns a RCSResourceObject.
139          *
140          * @throws RcsPlatformException
141          *             If registering a resource is failed.
142          *
143          */
144         public RcsResourceObject build() {
145             return nativeBuild(mUri, mType, mInterface, mIsObservable,
146                     mIsDiscovervable, mAttributes);
147         }
148     }
149
150     /**
151      * This provides the way to get the attributes of RcsResourceObject with
152      * lock.
153      * When a thread holds the lock, the other threads will be pending until the
154      * lock is released by unlock.
155      *
156      * Here is the standard idiom for AttributesLock:
157      *
158      * <pre>
159      * {@code
160      * AttributesLock lock = rcsResourceObject.getAttributesLock();
161      *
162      * try {
163      *     lock.lock();
164      *
165      *     ....
166      *
167      *     lock.apply();
168      * } finally {
169      *     lock.unlock();
170      * }
171      * }
172      * </pre>
173      */
174     public static class AttributesLock {
175
176         private final WeakReference<RcsResourceObject> mResourceObjectRef;
177
178         private RcsLockedAttributes mCurrentAttributes;
179
180         private AttributesLock(RcsResourceObject resourceObj) {
181             mResourceObjectRef = new WeakReference<RcsResourceObject>(
182                     resourceObj);
183         }
184
185         private RcsResourceObject ensureResourceObject() throws RcsException {
186             final RcsResourceObject object = mResourceObjectRef.get();
187
188             if (object == null || object.isDestroyed()) {
189                 throw new RcsDestroyedObjectException(
190                         "The object is already destroyed!");
191             }
192
193             return object;
194         }
195
196         /**
197          * Locks the attributes of the RcsResourceObject and returns locked
198          * attributes that can be modified until unlocked.
199          *
200          * @return Locked attributes.
201          *
202          * @throws RcsException
203          *             if the RcsResourceObject is destroyed
204          */
205         public RcsLockedAttributes lock() throws RcsException {
206             return mCurrentAttributes = new RcsLockedAttributes(
207                     ensureResourceObject());
208         }
209
210         /**
211          * Changes the state to unlock of the attributes of the
212          * RcsResourceObject.
213          *
214          */
215         public void unlock() {
216             if (mCurrentAttributes == null) return;
217
218             mCurrentAttributes.setUnlockState();
219             mCurrentAttributes = null;
220         }
221
222         /**
223          * Applies the modified attributes to the RcsResourceObject.
224          *
225          * @throws RcsIllegalStateException
226          *             if not in locked state
227          */
228         public void apply() throws RcsIllegalStateException {
229             if (mCurrentAttributes == null) {
230                 throw new RcsIllegalStateException("it is not locked state.");
231             }
232             mCurrentAttributes.apply();
233         }
234     }
235
236     private static native RcsResourceObject nativeBuild(String uri,
237             String resourceType, String resourceInterface, boolean isObservable,
238             boolean isDiscoverable, RcsResourceAttributes attributes);
239
240     private native void nativeSetAttribute(String key, RcsValue value);
241
242     private native RcsValue nativeGetAttributeValue(String key);
243
244     private native boolean nativeRemoveAttribute(String key);
245
246     private native boolean nativeContainsAttribute(String key);
247
248     private native RcsResourceAttributes nativeGetAttributes();
249
250     private native boolean nativeIsObservable();
251
252     private native boolean nativeIsDiscoverable();
253
254     private native void nativeNotify();
255
256     private native void nativeSetAutoNotifyPolicy(AutoNotifyPolicy policy);
257
258     private native AutoNotifyPolicy nativeGetAutoNotifyPolicy();
259
260     private native void nativeSetSetRequestHandlerPolicy(
261             SetRequestHandlerPolicy policy);
262
263     private native SetRequestHandlerPolicy nativeGetSetRequestHandlerPolicy();
264
265     private native void nativeSetGetRequestHandler(GetRequestHandler handler);
266
267     private native void nativeSetSetRequestHandler(SetRequestHandler handler);
268
269     private native void nativeAddAttributeUpdatedListener(String key,
270             OnAttributeUpdatedListener listener);
271
272     private native boolean nativeRemoveAttributeUpdatedListener(String key);
273
274     private RcsResourceObject() {
275     }
276
277     /**
278      * Represents the policy of AutoNotify function of RCSResourceObject class
279      * In accord with this, observers are notified of attributes that are
280      * changed or updated.
281      *
282      * <p>
283      * Attributes are changed or updated according to execution of some
284      * functions which modify attributes or receipt of set requests.
285      *
286      * @see setAttribute
287      * @see removeAttribute
288      * @see getAttributesLock
289      *
290      */
291     public enum AutoNotifyPolicy {
292         /** Never */
293         NEVER,
294
295         /** Always */
296         ALWAYS,
297
298         /** When attributes are changed */
299         UPDATED
300     }
301
302     /**
303      * Represents the policy of set-request handler.
304      * In accord with this, the RCSResourceObject decides whether a set-request
305      * is
306      * acceptable or not.
307      */
308     public enum SetRequestHandlerPolicy {
309         /**
310          * Requests will be ignored if attributes of the request contain
311          * a new key or a value that has different type from the current
312          * value of the key.
313          */
314         NEVER,
315
316         /**
317          * The attributes of the request will be applied unconditionally
318          * even if there are new name or type conflicts.
319          */
320         ACCEPT
321     }
322
323     /**
324      * Interface definition for a handler to be invoked when a get request is
325      * received.
326      * <p>
327      * The handler will be called first when a get request is received, before
328      * the RCSResourceObject handles.
329      *
330      * @see setGetRequestHandler
331      */
332     public interface GetRequestHandler {
333
334         /**
335          * Called when received a get request from the client.
336          *
337          * @param request
338          *            Request information.
339          * @param attributes
340          *            The attributes of the request.
341          *
342          * @return A response to be sent.
343          *
344          * @see RcsGetResponse
345          */
346         RcsGetResponse onGetRequested(RcsRequest request,
347                 RcsResourceAttributes attributes);
348
349     }
350
351     /**
352      * Interface definition for a handler to be invoked when a set request is
353      * received.
354      * <p>
355      * The handler will be called first when a get request is received, before
356      * the RCSResourceObject handles. If the attributes are modified in the
357      * callback, the modified attributes will be set in the RCSResourceObject if
358      * the request is not ignored.
359      *
360      * @see setGetRequestHandler
361      */
362     public interface SetRequestHandler {
363
364         /**
365          * Called when received a set request from the client.
366          *
367          * @param request
368          *            request information
369          * @param attributes
370          *            the attributes of the request.
371          *            it will be applied to the RcsResourceObject
372          *
373          * @return A response indicating how to handle this request.
374          *
375          * @see RcsSetResponse
376          */
377         RcsSetResponse onSetRequested(RcsRequest request,
378                 RcsResourceAttributes attributes);
379
380     }
381
382     /**
383      * Interface definition for a callback to be invoked when an attribute is
384      * updated.
385      */
386     public interface OnAttributeUpdatedListener {
387
388         /**
389          * Called when an attribute value is updated.
390          *
391          * @param oldValue
392          *            the attribute value before updated
393          * @param newValue
394          *            the current resource attribute value
395          */
396         void onAttributeUpdated(RcsValue oldValue, RcsValue newValue);
397     }
398
399     private void assertAlive() throws RcsException {
400         if (!hasHandle()) {
401             throw new RcsDestroyedObjectException(
402                     "The object is already destroyed!");
403         }
404     }
405
406     /**
407      * Sets a particular attribute value.
408      *
409      * @param key
410      *            key with which the specified value is to be associated
411      * @param value
412      *            value to be associated with the specified key
413      *
414      * @throws RcsDestroyedObjectException
415      *             if the object is destroyed
416      * @throws NullPointerException
417      *             if key or value is null
418      *
419      */
420     public void setAttribute(String key, RcsValue value) throws RcsException {
421         assertAlive();
422
423         if (key == null) throw new NullPointerException("key is null");
424         if (value == null) throw new NullPointerException("value is null");
425
426         nativeSetAttribute(key, value);
427     }
428
429     /**
430      * Returns a copied attribute value associated with the supplied key.
431      *
432      * @param key
433      *            the key whose associated value is to be returned
434      *
435      * @return the value to which the specified key is mapped, or null if no
436      *         attribute for the key
437      *
438      * @throws RcsDestroyedObjectException
439      *             if the object is destroyed
440      * @throws NullPointerException
441      *             if key is null
442      */
443     public RcsValue getAttributeValue(String key) throws RcsException {
444         assertAlive();
445
446         if (key == null) throw new NullPointerException("key is null");
447         return nativeGetAttributeValue(key);
448     }
449
450     /**
451      * Removes the mapping for a key from the attributes if it is present.
452      *
453      * @param key
454      *            key whose mapping is to be removed
455      *
456      * @return true if the key is present and the the value mapped is removed.
457      *
458      * @throws RcsDestroyedObjectException
459      *             if the object is destroyed
460      * @throws NullPointerException
461      *             if key is null
462      */
463     public boolean removeAttribute(String key) throws RcsException {
464         assertAlive();
465
466         if (key == null) throw new NullPointerException("key is null");
467         return nativeRemoveAttribute(key);
468     }
469
470     /**
471      * Returns true if the attributes contains a mapping for the specified key.
472      *
473      * @param key
474      *            key whose presence is to be tested
475      *
476      * @return true if the attributes contains a mapping for the specified key.
477      *
478      * @throws RcsDestroyedObjectException
479      *             if the object is destroyed
480      * @throws NullPointerException
481      *             if key is null
482      */
483     public boolean containsAttribute(String key) throws RcsException {
484         assertAlive();
485
486         if (key == null) throw new NullPointerException("key is null");
487         return nativeContainsAttribute(key);
488     }
489
490     /**
491      * Returns a copied attributes of the RCSResourceObject.
492      * To modify the attributes, use {@link AttributesLock}.
493      *
494      * @throws RcsDestroyedObjectException
495      *             if the object is destroyed
496      *
497      * @see getAttributesLock
498      */
499     public RcsResourceAttributes getAttributes() throws RcsException {
500         assertAlive();
501
502         return nativeGetAttributes();
503     }
504
505     /**
506      * Returns an AttributesLock for this RcsResourceObject.
507      *
508      * @throws RcsDestroyedObjectException
509      *             if the object is destroyed
510      */
511     public AttributesLock getAttributesLock() throws RcsException {
512         assertAlive();
513
514         return new AttributesLock(this);
515     }
516
517     /**
518      * Checks whether the resource is observable or not.
519      *
520      * @throws RcsDestroyedObjectException
521      *             if the object is destroyed
522      */
523     public boolean isObservable() throws RcsException {
524         assertAlive();
525
526         return nativeIsObservable();
527     }
528
529     /**
530      * Checks whether the resource is discoverable or not.
531      *
532      * @throws RcsDestroyedObjectException
533      *             if the object is destroyed
534      */
535     public boolean isDiscoverable() throws RcsException {
536         assertAlive();
537
538         return nativeIsDiscoverable();
539     }
540
541     /**
542      * Sets the get request handler. To remove handler, pass null.
543      *
544      * Default behavior is {@link RcsGetResponse#defaultAction()}.
545      *
546      * @throws RcsDestroyedObjectException
547      *             if the object is destroyed
548      */
549     public void setGetRequestHandler(GetRequestHandler handler)
550             throws RcsException {
551         assertAlive();
552
553         nativeSetGetRequestHandler(handler);
554     }
555
556     /**
557      * Sets the set request handler. To remove handler, pass null.
558      *
559      * Default behavior is {@link RcsSetResponse#defaultAction()}.
560      *
561      * @throws RcsDestroyedObjectException
562      *             if the object is destroyed
563      *
564      */
565     public void setSetRequestHandler(SetRequestHandler handler)
566             throws RcsException {
567         assertAlive();
568
569         nativeSetSetRequestHandler(handler);
570     }
571
572     /**
573      * Adds a listener for a particular attribute updated.
574      *
575      * @param key
576      *            the interested attribute's key
577      * @param listener
578      *            listener to be invoked
579      *
580      * @throws NullPointerException
581      *             if key or listener is null
582      * @throws RcsDestroyedObjectException
583      *             if the object is destroyed
584      */
585     public void addAttributeUpdatedListener(String key,
586             OnAttributeUpdatedListener listener) throws RcsException {
587         assertAlive();
588
589         if (key == null) {
590             throw new NullPointerException("key is null.");
591         }
592         if (listener == null) {
593             throw new NullPointerException("listener is null.");
594         }
595
596         nativeAddAttributeUpdatedListener(key, listener);
597     }
598
599     /**
600      * Removes a listener for a particular attribute updated.
601      *
602      * @param key
603      *            key the key associated with the listener to be removed
604      *
605      * @return true if the listener added with same key exists and is removed.
606      *
607      * @throws RcsDestroyedObjectException
608      *             if the object is destroyed
609      * @throws NullPointerException
610      *             if key is null
611      */
612     public boolean removeAttributeUpdatedListener(String key)
613             throws RcsException {
614         assertAlive();
615
616         if (key == null) throw new NullPointerException("key is null");
617         return nativeRemoveAttributeUpdatedListener(key);
618     }
619
620     /**
621      * Notifies all observers of the current attributes.
622      *
623      * @throws RcsDestroyedObjectException
624      *             if the object is destroyed
625      * @throws RcsPlatformException
626      *             if the operation failed
627      */
628     public void notifyObservers() throws RcsException {
629         assertAlive();
630
631         nativeNotify();
632     }
633
634     /**
635      * Sets auto notify policy
636      *
637      * @param policy
638      *            policy to be set
639      *
640      * @throws RcsDestroyedObjectException
641      *             if the object is destroyed
642      *
643      */
644     public void setAutoNotifyPolicy(AutoNotifyPolicy policy)
645             throws RcsException {
646         assertAlive();
647
648         if (policy == null) throw new NullPointerException("policy is null");
649         nativeSetAutoNotifyPolicy(policy);
650     }
651
652     /**
653      * Returns the current policy
654      *
655      * @throws RcsDestroyedObjectException
656      *             if the object is destroyed
657      *
658      */
659     public AutoNotifyPolicy getAutoNotifyPolicy() throws RcsException {
660         assertAlive();
661
662         return nativeGetAutoNotifyPolicy();
663     }
664
665     /**
666      * Sets the policy for handling a set request.
667      *
668      * @param policy
669      *            policy to be set
670      *
671      * @throws RcsDestroyedObjectException
672      *             if the object is destroyed
673      *
674      */
675     public void setSetRequestHandlerPolicy(SetRequestHandlerPolicy policy)
676             throws RcsException {
677         assertAlive();
678
679         if (policy == null) throw new NullPointerException("policy is null");
680         nativeSetSetRequestHandlerPolicy(policy);
681     }
682
683     /**
684      * Returns the current policy.
685      *
686      * @throws RcsDestroyedObjectException
687      *             if the object is destroyed
688      */
689     public SetRequestHandlerPolicy getSetRequestHandlerPolicy()
690             throws RcsException {
691         assertAlive();
692
693         return nativeGetSetRequestHandlerPolicy();
694     }
695
696     private boolean isDestroyed() {
697         return !hasHandle();
698     }
699
700     /**
701      * Unregister the resource and reclaims all resources used by this object.
702      * This must be called if the resource is not used any longer.
703      *
704      */
705     public void destroy() {
706         super.dispose();
707     }
708 }