001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements. See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache license, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License. You may obtain a copy of the License at
008     *
009     *      http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the license for the specific language governing permissions and
015     * limitations under the license.
016     */
017    package org.apache.logging.log4j.core.appender.db.jpa.converter;
018    
019    import javax.persistence.AttributeConverter;
020    import javax.persistence.Converter;
021    
022    import org.apache.logging.log4j.util.Strings;
023    
024    /**
025     * A JPA 2.1 attribute converter for {@link StackTraceElement}s in {@link org.apache.logging.log4j.core.LogEvent}s. This
026     * converter is capable of converting both to and from {@link String}s.
027     */
028    @Converter(autoApply = false)
029    public class StackTraceElementAttributeConverter implements AttributeConverter<StackTraceElement, String> {
030        private static final int UNKNOWN_SOURCE = -1;
031    
032        private static final int NATIVE_METHOD = -2;
033    
034        @Override
035        public String convertToDatabaseColumn(final StackTraceElement element) {
036            if (element == null) {
037                return null;
038            }
039    
040            return element.toString();
041        }
042    
043        @Override
044        public StackTraceElement convertToEntityAttribute(final String s) {
045            if (Strings.isEmpty(s)) {
046                return null;
047            }
048    
049            return StackTraceElementAttributeConverter.convertString(s);
050        }
051    
052        static StackTraceElement convertString(final String s) {
053            final int open = s.indexOf("(");
054    
055            final String classMethod = s.substring(0, open);
056            final String className = classMethod.substring(0, classMethod.lastIndexOf("."));
057            final String methodName = classMethod.substring(classMethod.lastIndexOf(".") + 1);
058    
059            final String parenthesisContents = s.substring(open + 1, s.indexOf(")"));
060    
061            String fileName = null;
062            int lineNumber = UNKNOWN_SOURCE;
063            if ("Native Method".equals(parenthesisContents)) {
064                lineNumber = NATIVE_METHOD;
065            } else if (!"Unknown Source".equals(parenthesisContents)) {
066                final int colon = parenthesisContents.indexOf(":");
067                if (colon > UNKNOWN_SOURCE) {
068                    fileName = parenthesisContents.substring(0, colon);
069                    try {
070                        lineNumber = Integer.parseInt(parenthesisContents.substring(colon + 1));
071                    } catch (final NumberFormatException ignore) {
072                        // we don't care
073                    }
074                } else {
075                    fileName = parenthesisContents.substring(0);
076                }
077            }
078    
079            return new StackTraceElement(className, methodName, fileName, lineNumber);
080        }
081    }