001/*
002 * BridJ - Dynamic and blazing-fast native interop for Java.
003 * http://bridj.googlecode.com/
004 *
005 * Copyright (c) 2010-2013, Olivier Chafik (http://ochafik.com/)
006 * All rights reserved.
007 *
008 * Redistribution and use in source and binary forms, with or without
009 * modification, are permitted provided that the following conditions are met:
010 * 
011 *     * Redistributions of source code must retain the above copyright
012 *       notice, this list of conditions and the following disclaimer.
013 *     * Redistributions in binary form must reproduce the above copyright
014 *       notice, this list of conditions and the following disclaimer in the
015 *       documentation and/or other materials provided with the distribution.
016 *     * Neither the name of Olivier Chafik nor the
017 *       names of its contributors may be used to endorse or promote products
018 *       derived from this software without specific prior written permission.
019 * 
020 * THIS SOFTWARE IS PROVIDED BY OLIVIER CHAFIK AND CONTRIBUTORS ``AS IS'' AND ANY
021 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
022 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
023 * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
024 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
025 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
026 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
027 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
028 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
029 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
030 */
031package org.bridj;
032
033import java.util.List;
034import java.util.concurrent.ConcurrentHashMap;
035import org.bridj.ann.Struct;
036
037/**
038 * Interface for type customizers that can be used to perform platform-specific
039 * type adjustments or other hacks.<br>
040 * A type customizer can be specified with {@link Struct#customizer() }.<br>
041 * Each implementation must have a default constructor, and an unique instance
042 * of each implementation class will be cached by {@link StructCustomizer#getInstance(java.lang.Class)
043 * }.
044 *
045 * @deprecated The StructIO API is subject to future changes. Use this with care
046 * and be prepared to migrate your code...
047 */
048@Deprecated
049public class StructCustomizer {
050
051    /**
052     * Last chance to remove field declarations
053     */
054    public void beforeAggregation(StructDescription desc, List<StructFieldDeclaration> fieldDecls) {
055    }
056
057    /**
058     * Last chance to remove aggregated fields
059     */
060    public void beforeLayout(StructDescription desc, List<StructFieldDescription> aggregatedFields) {
061    }
062
063    /**
064     * This method can alter the aggregated fields and may even call again the
065     * performLayout(aggregatedFields) method. This is before field offsets and
066     * sizes are propagated to field declarations.
067     */
068    public void afterLayout(StructDescription desc, List<StructFieldDescription> aggregatedFields) {
069    }
070
071    /**
072     * Called after everything is setup in the StructIO.<br>
073     * It is the most dangerous callback, here it's advised to only call the
074     * prependBytes, appendBytes and setFieldOffset methods.
075     */
076    public void afterBuild(StructDescription desc) {
077    }
078    private static StructCustomizer dummyCustomizer = new StructCustomizer();
079    private static ConcurrentHashMap<Class, StructCustomizer> customizers = new ConcurrentHashMap<Class, StructCustomizer>();
080
081    static StructCustomizer getInstance(Class<?> structClass) {
082        StructCustomizer c = customizers.get(structClass);
083        if (c == null) {
084            Struct s = structClass.getAnnotation(Struct.class);
085            if (s != null) {
086                Class<? extends StructCustomizer> customizerClass = s.customizer();
087                if (customizerClass != null && customizerClass != StructCustomizer.class) {
088                    try {
089                        c = customizerClass.newInstance();
090                    } catch (Throwable th) {
091                        throw new RuntimeException("Failed to create customizer of class " + customizerClass.getName() + " for struct class " + structClass.getName() + " : " + th, th);
092                    }
093                }
094            }
095            if (c == null) {
096                c = dummyCustomizer;
097            }
098            StructCustomizer existingConcurrentCustomizer =
099                    customizers.putIfAbsent(structClass, c);
100            if (existingConcurrentCustomizer != null) {
101                return existingConcurrentCustomizer;
102            }
103        }
104        return c;
105    }
106}