001/*
002 * jPOS Project [http://jpos.org]
003 * Copyright (C) 2000-2026 jPOS Software SRL
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Affero General Public License as
007 * published by the Free Software Foundation, either version 3 of the
008 * License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU Affero General Public License for more details.
014 *
015 * You should have received a copy of the GNU Affero General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018
019package org.jpos.util;
020
021import java.util.regex.Matcher;
022import java.util.regex.Pattern;
023
024/**
025 * Return Caller's short class name, method and line number
026 */
027public class Caller {
028    /** Utility class; instances carry no state. */
029    public Caller() {}
030    private static String JAVA_ID_PATTERN = "(\\p{javaJavaIdentifierStart}\\p{javaJavaIdentifierPart}*)\\.*";
031    private static Pattern FQCN = Pattern.compile(JAVA_ID_PATTERN + "(\\." + JAVA_ID_PATTERN + ")*");
032    /**
033     * Returns information for the immediate caller of the method that calls this helper.
034     *
035     * @return abbreviated {@code class.method:line} string
036     */
037    public static String info() {
038        return info(1);
039    }
040
041    /**
042     * Returns information for the caller {@code pos} frames above the immediate caller.
043     *
044     * @param pos additional stack frames to skip past the immediate caller
045     * @return abbreviated {@code class.method:line} string
046     */
047    public static String info(int pos) {
048        return info (Thread.currentThread().getStackTrace()[2+pos]);
049    }
050
051    /**
052     * Formats a stack trace element as {@code abbreviatedClass.method:line}.
053     *
054     * @param st stack frame to format
055     * @return abbreviated {@code class.method:line} string
056     */
057    public static String info (StackTraceElement st) {
058        String clazz = st.getClassName();
059        Matcher matcher = FQCN.matcher(clazz);
060        StringBuilder sb = new StringBuilder();
061        while (matcher.find()) {
062            sb.append(matcher.hitEnd() ? matcher.group(1) : matcher.group(1).charAt(0));
063            sb.append('.');
064        }
065        return sb.append(st.getMethodName())
066          .append(':')
067          .append(st.getLineNumber())
068          .toString();
069    }
070
071
072    /**
073     * Abbreviates a fully-qualified class name by collapsing every package segment
074     * to its first character (e.g. {@code o.j.u.Caller}).
075     *
076     * @param clazz fully-qualified class name
077     * @return the abbreviated class name
078     */
079    public static String shortClassName(String clazz) {
080        Matcher matcher = FQCN.matcher(clazz);
081        StringBuilder sb = new StringBuilder();
082        while (matcher.find()) {
083            if (matcher.hitEnd()) {
084                sb.append(matcher.group(1));
085                break;
086            }
087            else {
088                sb.append(matcher.group(1).charAt(0));
089                sb.append('.');
090            }
091        }
092        return sb.toString();
093    }
094}