001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License. You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied. See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.commons.weaver.model;
020
021import java.lang.reflect.Constructor;
022import java.lang.reflect.Field;
023import java.lang.reflect.Method;
024import java.util.Collections;
025import java.util.Comparator;
026import java.util.concurrent.ConcurrentNavigableMap;
027import java.util.concurrent.ConcurrentSkipListMap;
028
029import org.apache.commons.weaver.utils.Args;
030
031/**
032 * {@link Weavable} {@link Class}.
033 *
034 * @param <T> type
035 */
036public class WeavableClass<T> extends NestedWeavable<WeavableClass<T>, Class<T>, WeavablePackage, Package> {
037    private final ConcurrentNavigableMap<String, WeavableField<T>> fields =
038        new ConcurrentSkipListMap<String, WeavableField<T>>();
039
040    private final ConcurrentNavigableMap<Constructor<T>, WeavableConstructor<T>> ctors =
041        new ConcurrentSkipListMap<Constructor<T>, WeavableConstructor<T>>(new Comparator<Constructor<?>>() {
042
043            @Override
044            public int compare(final Constructor<?> ctor1, final Constructor<?> ctor2) {
045                return Args.compare(ctor1.getParameterTypes(), ctor2.getParameterTypes());
046            }
047        });
048
049    private final ConcurrentNavigableMap<Method, WeavableMethod<T>> methods =
050        new ConcurrentSkipListMap<Method, WeavableMethod<T>>(new Comparator<Method>() {
051
052            @Override
053            public int compare(final Method methd1, final Method methd2) {
054                final int result = methd1.getName().compareTo(methd2.getName());
055                return result == 0 ? Args.compare(methd1.getParameterTypes(), methd2.getParameterTypes()) : result;
056            }
057        });
058
059    /**
060     * Create a new {@link WeavableClass} instance.
061     * @param target {@link Class}
062     * @param parent {@link WeavablePackage} enclosing
063     */
064    public WeavableClass(final Class<T> target, final WeavablePackage parent) {
065        super(target, parent);
066    }
067
068    /**
069     * Get a {@link WeavableField} representing {@code fld}.
070     * @param fld to wrap
071     * @return {@link WeavableField}
072     */
073    public WeavableField<T> getWeavable(final Field fld) {
074        final String key = fld.getName();
075        if (fields.containsKey(key)) {
076            final WeavableField<T> result = fields.get(key);
077            return result;
078        }
079        final WeavableField<T> result = new WeavableField<T>(fld, this);
080        final WeavableField<T> faster = fields.putIfAbsent(key, result);
081        return faster == null ? result : faster;
082    }
083
084    /**
085     * Get a {@link WeavableMethod} representing {@code mt}.
086     * @param methd to wrap
087     * @return {@link WeavableMethod}
088     */
089    public WeavableMethod<T> getWeavable(final Method methd) {
090        if (methods.containsKey(methd)) {
091            final WeavableMethod<T> result = methods.get(methd);
092            return result;
093        }
094        final WeavableMethod<T> result = new WeavableMethod<T>(methd, this);
095        final WeavableMethod<T> faster = methods.putIfAbsent(methd, result);
096        return faster == null ? result : faster;
097    }
098
099    /**
100     * Get a {@link WeavableConstructor} representing {@code ctor}.
101     * @param ctor to wrap
102     * @return {@link WeavableConstructor}
103     */
104    public WeavableConstructor<T> getWeavable(final Constructor<T> ctor) {
105        if (ctors.containsKey(ctor)) {
106            final WeavableConstructor<T> result = ctors.get(ctor);
107            return result;
108        }
109        final WeavableConstructor<T> result = new WeavableConstructor<T>(ctor, this);
110        final WeavableConstructor<T> faster = ctors.putIfAbsent(ctor, result);
111        return faster == null ? result : faster;
112    }
113
114    /**
115     * Get {@link WeavableField}s of this {@link WeavableClass}.
116     * @return {@link Iterable}
117     */
118    public Iterable<WeavableField<T>> getFields() {
119        return Collections.unmodifiableCollection(fields.values());
120    }
121
122    /**
123     * Get {@link WeavableConstructor}s of this {@link WeavableClass}.
124     * @return {@link Iterable}
125     */
126    public Iterable<WeavableConstructor<T>> getConstructors() {
127        return Collections.unmodifiableCollection(ctors.values());
128    }
129
130    /**
131     * Get {@link WeavableMethod}s of this {@link WeavableClass}.
132     * @return {@link Iterable}
133     */
134    public Iterable<WeavableMethod<T>> getMethods() {
135        return Collections.unmodifiableCollection(methods.values());
136    }
137
138    /**
139     * {@inheritDoc}
140     */
141    @Override
142    protected int localCompareTo(final WeavableClass<T> obj) {
143        return getTarget().getName().compareTo(obj.getTarget().getName());
144    }
145}