001/*
002 * Copyright 2020 Leibniz-Institut für Analytische Wissenschaften – ISAS – e.V..
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package de.isas.mztab2.model;
017
018import java.lang.reflect.InvocationTargetException;
019import java.lang.reflect.Proxy;
020import javax.validation.ValidationException;
021
022/**
023 * Indexed elements (IDs) define a unique ID for a collection of multiple
024 * metadata elements of the same type within the mzTab-M document, e.g. for
025 * sample, assay, study variable etc.
026 *
027 * @author nilshoffmann
028 */
029public interface IndexedElement {
030
031    /**
032     * Returns the id of the indexed element. May be null.
033     *
034     * @return the id.
035     */
036    public Integer getId();
037
038    /**
039     * Create a new indexed element as a proxy of the provided element.
040     *
041     * @param element the element with a getId, hashCode and toString method to
042     * proxy.
043     * @return the indexed element proxy.
044     * @throws ValidationException if the passed in element can not be proxied.
045     */
046    public static IndexedElement of(Object element) {
047        IndexedElement proxyInstance = (IndexedElement) Proxy.newProxyInstance(
048                IndexedElement.class.getClassLoader(),
049                new Class[]{IndexedElement.class},
050                (proxy, method, methodArgs) -> {
051                    if (method.getName().equals("getId")) {
052
053                        try {
054                            Integer id = (Integer) element.getClass().getMethod("getId").invoke(element);
055                            return id;
056                        } catch (NoSuchMethodException ex) {
057                            throw new ValidationException(
058                                    "'id' field of " + element.toString() + " was not accessible by method getId! Missing method!");
059                        } catch (SecurityException ex) {
060                            throw new ValidationException(
061                                    "'id' field of " + element.toString() + " was not accessible by method getId! Access denied!");
062                        } catch (IllegalAccessException ex) {
063                            throw new ValidationException(
064                                    "'id' field of " + element.toString() + " was not accessible by method getId! Illegal access!");
065                        } catch (IllegalArgumentException ex) {
066                            throw new ValidationException(
067                                    "'id' field of " + element.toString() + " was not accessible by method getId! Illegal argument!");
068                        } catch (InvocationTargetException ex) {
069                            throw new ValidationException(
070                                    "'id' field of " + element.toString() + " was not accessible by method getId! Invalid invocation target!");
071                        }
072                    } else if (method.getName().equals("hashCode")) {
073                        return element.getClass().getMethod("hashCode").invoke(element);
074                    } else if (method.getName().equals("toString")) {
075                        return element.getClass().getMethod("toString").invoke(element);
076                    } else {
077                        throw new ValidationException(
078                                "Unsupported method: " + method.getName() + " on element of type " + element.getClass().getName());
079                    }
080                });
081        return proxyInstance;
082    }
083}