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         sRegisteredMarshalQueryables.add(queryable);
     41     }
     42 
     43     /**
     44      * Lookup a marshaler between {@code T} and {@code nativeType}.
     45      *
     46      * <p>Marshalers are looked up in the order they were registered; earlier registered
     47      * marshal queriers get priority.</p>
     48      *
     49      * @param typeToken The compile-time type reference for {@code T}
     50      * @param nativeType The native type, e.g. {@link CameraMetadataNative#TYPE_BYTE TYPE_BYTE}
     51      * @return marshaler a non-{@code null} marshaler that supports marshaling the type combo
     52      *
     53      * @throws UnsupportedOperationException If no marshaler matching the args could be found
     54      */
     55     @SuppressWarnings("unchecked")
     56     public static <T> Marshaler<T> getMarshaler(TypeReference<T> typeToken, int nativeType) {
     57         // TODO: can avoid making a new token each time by code-genning
     58         // the list of type tokens and native types from the keys (at the call sites)
     59         MarshalToken<T> marshalToken = new MarshalToken<T>(typeToken, nativeType);
     60 
     61         /*
     62          * Marshalers are instantiated lazily once they are looked up; successive lookups
     63          * will not instantiate new marshalers.
     64          */
     65         Marshaler<T> marshaler =
     66                 (Marshaler<T>) sMarshalerMap.get(marshalToken);
     67 
     68         if (sRegisteredMarshalQueryables.size() == 0) {
     69             throw new AssertionError("No available query marshalers registered");
     70         }
     71 
     72         if (marshaler == null) {
     73             // Query each marshaler to see if they support the native/managed type combination
     74             for (MarshalQueryable<?> potentialMarshaler : sRegisteredMarshalQueryables) {
     75 
     76                 MarshalQueryable<T> castedPotential =
     77                         (MarshalQueryable<T>)potentialMarshaler;
     78 
     79                 if (castedPotential.isTypeMappingSupported(typeToken, nativeType)) {
     80                     marshaler = castedPotential.createMarshaler(typeToken, nativeType);
     81                     break;
     82                 }
     83             }
     84 
     85             if (marshaler == null) {
     86                 throw new UnsupportedOperationException(
     87                         "Could not find marshaler that matches the requested " +
     88                                 "combination of type reference " +
     89                                 typeToken + " and native type " +
     90                                 MarshalHelpers.toStringNativeType(nativeType));
     91             }
     92 
     93             // Only put when no cached version exists to avoid +0.5ms lookup per call.
     94             sMarshalerMap.put(marshalToken, marshaler);
     95         }
     96 
     97         return marshaler;
     98     }
     99 
    100     private static class MarshalToken<T> {
    101         public MarshalToken(TypeReference<T> typeReference, int nativeType) {
    102             this.typeReference = typeReference;
    103             this.nativeType = nativeType;
    104             this.hash = typeReference.hashCode() ^ nativeType;
    105         }
    106 
    107         final TypeReference<T> typeReference;
    108         final int nativeType;
    109         private final int hash;
    110 
    111         @Override
    112         public boolean equals(Object other) {
    113             if (other instanceof MarshalToken<?>) {
    114                 MarshalToken<?> otherToken = (MarshalToken<?>)other;
    115                 return typeReference.equals(otherToken.typeReference) &&
    116                         nativeType == otherToken.nativeType;
    117             }
    118 
    119             return false;
    120         }
    121 
    122         @Override
    123         public int hashCode() {
    124             return hash;
    125         }
    126     }
    127 
    128     private static List<MarshalQueryable<?>> sRegisteredMarshalQueryables =
    129             new ArrayList<MarshalQueryable<?>>();
    130     private static HashMap<MarshalToken<?>, Marshaler<?>> sMarshalerMap =
    131             new HashMap<MarshalToken<?>, Marshaler<?>>();
    132 
    133     private MarshalRegistry() {
    134         throw new AssertionError();
    135     }
    136 }
    137