View Javadoc
1   /*
2    * Copyright (c) 2001-2017, Zoltan Farkas All Rights Reserved.
3    *
4    * This library is free software; you can redistribute it and/or
5    * modify it under the terms of the GNU Lesser General Public
6    * License as published by the Free Software Foundation; either
7    * version 2.1 of the License, or (at your option) any later version.
8    *
9    * This library is distributed in the hope that it will be useful,
10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   * GNU General Public License for more details.
13   *
14   * You should have received a copy of the GNU Lesser General Public
15   * License along with this program; if not, write to the Free Software
16   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17   *
18   * Additionally licensed with:
19   *
20   * Licensed under the Apache License, Version 2.0 (the "License");
21   * you may not use this file except in compliance with the License.
22   * You may obtain a copy of the License at
23   *
24   *      http://www.apache.org/licenses/LICENSE-2.0
25   *
26   * Unless required by applicable law or agreed to in writing, software
27   * distributed under the License is distributed on an "AS IS" BASIS,
28   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
29   * See the License for the specific language governing permissions and
30   * limitations under the License.
31   */
32  package org.spf4j.base.avro;
33  
34  import gnu.trove.map.TMap;
35  import java.util.ArrayDeque;
36  import java.util.ArrayList;
37  import java.util.Collections;
38  import java.util.Deque;
39  import java.util.List;
40  import java.util.Set;
41  import java.util.function.Consumer;
42  import javax.annotation.Nonnull;
43  import javax.annotation.Nullable;
44  import javax.annotation.ParametersAreNonnullByDefault;
45  import org.spf4j.base.Methods;
46  import org.spf4j.ds.IdentityHashSet;
47  import org.spf4j.log.Slf4jLogRecord;
48  
49  /**
50   * @author Zoltan Farkas
51   */
52  @ParametersAreNonnullByDefault
53  public final class Converters {
54  
55    public static final Method ROOT = new Method("JVM", "ROOT");
56  
57    private Converters() { }
58  
59    public static StackTraceElement convert(final java.lang.StackTraceElement stackTrace) {
60      String className = stackTrace.getClassName();
61      String fileName = stackTrace.getFileName();
62      return new StackTraceElement(new Method(className, stackTrace.getMethodName()),
63              fileName == null ? null :  new FileLocation(fileName, stackTrace.getLineNumber(), -1),
64              org.spf4j.base.PackageInfo.getPackageInfo(className));
65    }
66  
67    public static List<StackTraceElement> convert(final java.lang.StackTraceElement[] stackTraces) {
68      int l = stackTraces.length;
69      if (l == 0) {
70        return Collections.EMPTY_LIST;
71      }
72      List<StackTraceElement> result = new ArrayList<>(l);
73      for (java.lang.StackTraceElement st : stackTraces) {
74        result.add(convert(st));
75      }
76      return result;
77    }
78  
79    public static List<Throwable> convert(final java.lang.Throwable[] throwables, final Set<java.lang.Throwable> seen) {
80      int l = throwables.length;
81      if (l == 0) {
82        return Collections.EMPTY_LIST;
83      }
84      List<Throwable> result = new ArrayList<>(l);
85      for (java.lang.Throwable t : throwables) {
86        result.add(convert(t, seen));
87      }
88      return result;
89    }
90  
91    public static Throwable convert(final java.lang.Throwable throwable) {
92      return convert(throwable, new IdentityHashSet<>(4));
93    }
94  
95    public static Throwable convert(final java.lang.Throwable throwable,
96            final Set<java.lang.Throwable> seen) {
97      if (seen.contains(throwable)) {
98        return new Throwable(throwable.getClass().getName(),
99                "CIRCULAR REFERENCE:" + throwable.getMessage(),
100               Collections.EMPTY_LIST, null, Collections.EMPTY_LIST);
101     } else {
102       seen.add(throwable);
103     }
104     String message = throwable.getMessage();
105     if (throwable instanceof RemoteException) {
106         return new Throwable(throwable.getClass().getName(),
107                 message == null ? "" : message, convert(throwable.getStackTrace()),
108                 ((RemoteException) throwable).getRemoteCause(),
109                 convert(throwable.getSuppressed(), seen));
110     }
111     java.lang.Throwable cause = throwable.getCause();
112     return new Throwable(throwable.getClass().getName(),
113             message == null ? "" : message,
114             convert(throwable.getStackTrace()),
115             cause == null ? null : convert(cause, seen),
116             convert(throwable.getSuppressed(), seen));
117   }
118 
119   public static RemoteException convert(final String source, final Throwable throwable) {
120     return new RemoteException(source, throwable);
121   }
122 
123 
124   public static List<LogRecord> convert(final String origin, final String traceId,
125           final List<Slf4jLogRecord> logRecords) {
126     List<LogRecord> result = new ArrayList<>(logRecords.size());
127     for (Slf4jLogRecord log : logRecords) {
128       result.add(log.toLogRecord(origin, traceId));
129     }
130     return result;
131   }
132 
133 
134   public static int convert(final Method method, final org.spf4j.base.StackSamples node,
135           final int parentId, final int id,
136           final Consumer<StackSampleElement> handler) {
137 
138     final Deque<TraversalNode> dq = new ArrayDeque<>();
139     dq.addLast(new TraversalNode(method, node, parentId));
140     int nid = id;
141     while (!dq.isEmpty()) {
142       TraversalNode first = dq.removeFirst();
143       org.spf4j.base.StackSamples n = first.getNode();
144       StackSampleElement sample = new StackSampleElement(nid, first.getParentId(),
145               n.getSampleCount(), first.getMethod());
146       final TMap<Method, ? extends org.spf4j.base.StackSamples> subNodes = n.getSubNodes();
147       final int pid = nid;
148       if (subNodes != null) {
149         subNodes.forEachEntry((a, b) -> {
150           dq.addLast(new TraversalNode(a, b, pid));
151           return true;
152         });
153       }
154       handler.accept(sample);
155       nid++;
156     }
157     return nid;
158   }
159 
160 
161   @ParametersAreNonnullByDefault
162   private static final class TraversalNode {
163 
164     private final Method method;
165     private final org.spf4j.base.StackSamples node;
166     private final int parentId;
167 
168     TraversalNode(final Method method, final org.spf4j.base.StackSamples node, final int parentId) {
169       this.method = method;
170       this.node = node;
171       this.parentId = parentId;
172     }
173 
174     public Method getMethod() {
175       return method;
176     }
177 
178     public org.spf4j.base.StackSamples getNode() {
179       return node;
180     }
181 
182     public int getParentId() {
183       return parentId;
184     }
185 
186     @Override
187     public String toString() {
188       return "TraversalNode{" + "method=" + method + ", node=" + node + ", parentId=" + parentId + '}';
189     }
190 
191   }
192 
193   @Nonnull
194   public static List<StackSampleElement> convert(@Nullable final org.spf4j.base.StackSamples stackSamples) {
195     if (stackSamples != null) {
196         final List<StackSampleElement> samples = new ArrayList<>();
197         Converters.convert(Methods.ROOT, stackSamples, -1, 0, samples::add);
198         return samples;
199     } else {
200       return Collections.EMPTY_LIST;
201     }
202   }
203 
204 }