1 /*
2  * Copyright (C) 2014 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package android.hardware.camera2.marshal;
17 
18 import android.hardware.camera2.impl.CameraMetadataNative;
19 import android.hardware.camera2.utils.TypeReference;
20 
21 import java.util.ArrayList;
22 import java.util.HashMap;
23 import java.util.List;
24 
25 /**
26  * Registry of supported marshalers; add new query-able marshalers or lookup existing ones.</p>
27  */
28 public class MarshalRegistry {
29 
30     /**
31      * Register a marshal queryable for the managed type {@code T}.
32      *
33      * <p>Multiple marshal queryables for the same managed type {@code T} may be registered;
34      * this is desirable if they support different native types (e.g. marshaler 1 supports
35      * {@code Integer <-> TYPE_INT32}, marshaler 2 supports {@code Integer <-> TYPE_BYTE}.</p>
36      *
37      * @param queryable a non-{@code null} marshal queryable that supports marshaling {@code T}
38      */
registerMarshalQueryable(MarshalQueryable<T> queryable)39     public static <T> void registerMarshalQueryable(MarshalQueryable<T> queryable) {
40         synchronized(sMarshalLock) {
41             sRegisteredMarshalQueryables.add(queryable);
42         }
43     }
44 
45     /**
46      * Lookup a marshaler between {@code T} and {@code nativeType}.
47      *
48      * <p>Marshalers are looked up in the order they were registered; earlier registered
49      * marshal queriers get priority.</p>
50      *
51      * @param typeToken The compile-time type reference for {@code T}
52      * @param nativeType The native type, e.g. {@link CameraMetadataNative#TYPE_BYTE TYPE_BYTE}
53      * @return marshaler a non-{@code null} marshaler that supports marshaling the type combo
54      *
55      * @throws UnsupportedOperationException If no marshaler matching the args could be found
56      */
57     @SuppressWarnings("unchecked")
getMarshaler(TypeReference<T> typeToken, int nativeType)58     public static <T> Marshaler<T> getMarshaler(TypeReference<T> typeToken, int nativeType) {
59         synchronized(sMarshalLock) {
60             // TODO: can avoid making a new token each time by code-genning
61             // the list of type tokens and native types from the keys (at the call sites)
62             MarshalToken<T> marshalToken = new MarshalToken<T>(typeToken, nativeType);
63 
64             /*
65              * Marshalers are instantiated lazily once they are looked up; successive lookups
66              * will not instantiate new marshalers.
67              */
68             Marshaler<T> marshaler =
69                     (Marshaler<T>) sMarshalerMap.get(marshalToken);
70 
71             if (marshaler == null) {
72 
73                 if (sRegisteredMarshalQueryables.size() == 0) {
74                     throw new AssertionError("No available query marshalers registered");
75                 }
76 
77                 // Query each marshaler to see if they support the native/managed type combination
78                 for (MarshalQueryable<?> potentialMarshaler : sRegisteredMarshalQueryables) {
79 
80                     MarshalQueryable<T> castedPotential =
81                             (MarshalQueryable<T>)potentialMarshaler;
82 
83                     if (castedPotential.isTypeMappingSupported(typeToken, nativeType)) {
84                         marshaler = castedPotential.createMarshaler(typeToken, nativeType);
85                         break;
86                     }
87                 }
88 
89                 if (marshaler == null) {
90                     throw new UnsupportedOperationException(
91                         "Could not find marshaler that matches the requested " +
92                         "combination of type reference " +
93                         typeToken + " and native type " +
94                         MarshalHelpers.toStringNativeType(nativeType));
95                 }
96 
97                 // Only put when no cached version exists to avoid +0.5ms lookup per call.
98                 sMarshalerMap.put(marshalToken, marshaler);
99             }
100 
101             return marshaler;
102         }
103     }
104 
105     private static class MarshalToken<T> {
MarshalToken(TypeReference<T> typeReference, int nativeType)106         public MarshalToken(TypeReference<T> typeReference, int nativeType) {
107             this.typeReference = typeReference;
108             this.nativeType = nativeType;
109             this.hash = typeReference.hashCode() ^ nativeType;
110         }
111 
112         final TypeReference<T> typeReference;
113         final int nativeType;
114         private final int hash;
115 
116         @Override
equals(Object other)117         public boolean equals(Object other) {
118             if (other instanceof MarshalToken<?>) {
119                 MarshalToken<?> otherToken = (MarshalToken<?>)other;
120                 return typeReference.equals(otherToken.typeReference) &&
121                         nativeType == otherToken.nativeType;
122             }
123 
124             return false;
125         }
126 
127         @Override
hashCode()128         public int hashCode() {
129             return hash;
130         }
131     }
132 
133     // Control access to the static data structures below
134     private static final Object sMarshalLock = new Object();
135 
136     private static final List<MarshalQueryable<?>> sRegisteredMarshalQueryables =
137             new ArrayList<MarshalQueryable<?>>();
138     private static final HashMap<MarshalToken<?>, Marshaler<?>> sMarshalerMap =
139             new HashMap<MarshalToken<?>, Marshaler<?>>();
140 
MarshalRegistry()141     private MarshalRegistry() {
142         throw new AssertionError();
143     }
144 }
145