Home | History | Annotate | Download | only in marshal
      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      */
     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")
     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> {
    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
    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
    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 
    141     private MarshalRegistry() {
    142         throw new AssertionError();
    143     }
    144 }
    145