Skip to content

Commit

Permalink
#27. Growing up PatternsFile
Browse files Browse the repository at this point in the history
  • Loading branch information
kocherovms committed Apr 1, 2016
1 parent c03b150 commit bdcb0e7
Show file tree
Hide file tree
Showing 2 changed files with 249 additions and 0 deletions.
126 changes: 126 additions & 0 deletions src/main/java/com/develorium/metracer/PatternsFile.java
@@ -0,0 +1,126 @@
/*
* Copyright 2015-2016 Michael Kocherov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.develorium.metracer;

import java.util.*;
import java.util.regex.*;
import java.io.*;

public class PatternsFile {
private String classMatchingPattern = null;
private String methodMatchingPattern = null;

public PatternsFile(InputStream theInputStream) throws IOException {
Objects.requireNonNull(theInputStream);
loadPatterns(theInputStream);
}

public PatternsFile(OutputStream theOutputStream) {
Objects.requireNonNull(theOutputStream);
}

public String getClassMatchingPattern() {
return classMatchingPattern;
}

public String getMethodMatchingPattern() {
return methodMatchingPattern;
}

public void consumePatterns(String thePatterns, String theContext) {
//
}

private void loadPatterns(InputStream theInputStream) throws IOException {
BufferedReader inputReader = new BufferedReader(new InputStreamReader(theInputStream));
String rawLine = null;
StringBuilder classMatchingPatternBuilder = new StringBuilder();
StringBuilder methodMatchingPatternBuilder = new StringBuilder();
Set<String> classNames = new HashSet<String>();
Set<String> classNamePlusMethodNames = new HashSet<String>();
Pattern anySpacePattern = Pattern.compile("\\s");

while((rawLine = inputReader.readLine()) != null) {
String line = rawLine.trim();

if(line.startsWith("#") || line.isEmpty())
continue;

int separatorIndex = line.indexOf("::");

if(separatorIndex == -1 || separatorIndex == 0 || (separatorIndex + 2) >= line.length())
throw new RuntimeException(String.format("Cannot extract class and method names from line \"%s\"", line));

if(anySpacePattern.matcher(line).find())
throw new RuntimeException(String.format("Line \"%s\" contains unallowed spaces, tabs or other separators", line));

String className = line.substring(0, separatorIndex);
String methodName = line.substring(separatorIndex + 2);
String classNamePlusMethodName = String.format("%s::%s", className, methodName);

if(!classNames.contains(className)) {
classNames.add(className);

if(classMatchingPatternBuilder.length() > 0)
classMatchingPatternBuilder.append("|");

classMatchingPatternBuilder.append(getRegexFriendlyString(className));
}

methodName = getRegexFriendlyString(methodName);

if(!classNamePlusMethodNames.contains(classNamePlusMethodName)) {
classNamePlusMethodNames.add(classNamePlusMethodName);

if(methodMatchingPatternBuilder.length() > 0)
methodMatchingPatternBuilder.append("|");

methodMatchingPatternBuilder.append(getRegexFriendlyString(classNamePlusMethodName));
}
}

if(classMatchingPatternBuilder.length() > 0) {
classMatchingPattern = "(" + classMatchingPatternBuilder.toString() + ")";

if(methodMatchingPatternBuilder.length() > 0)
methodMatchingPattern = "(" + methodMatchingPatternBuilder.toString() + ")";
}
}

private String getRegexFriendlyString(String theUnfriendlyString) {
StringBuilder friendlyString = new StringBuilder();

for(int i = 0; i < theUnfriendlyString.length(); ++i) {
int codePoint = theUnfriendlyString.codePointAt(i);

if(Character.isLetterOrDigit(codePoint) || codePoint == '_' || codePoint == ':') {
friendlyString.appendCodePoint(codePoint);
continue;
}

if(codePoint == '$' || codePoint == '.') {
friendlyString.append("\\");
friendlyString.appendCodePoint(codePoint);
continue;
}

friendlyString.append('.');
}

return friendlyString.toString();
}
}
123 changes: 123 additions & 0 deletions src/test/java/com/develorium/metracer/PatternsFileTest.java
@@ -0,0 +1,123 @@
/*
* Copyright 2015-2016 Michael Kocherov
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.develorium.metracer;

import java.util.*;
import java.util.regex.*;
import java.io.*;
import junit.framework.Assert;
import org.junit.Test;

public class PatternsFileTest {
@Test
public void testLoading() throws IOException {
String content =
"com.develorium.metracer.TestA::method1\n" +
"com.develorium.metracer.TestA::method2\n" +
"com.develorium.metracer.TestA::method3\n" +
"com.develorium.metracer.TestB::method0\n" +
"com.develorium.metracer.TestC$1::method2\n" +
"com.develorium.metracer.TestD_DD::m_ethod\n";
ByteArrayInputStream inputStream = new ByteArrayInputStream(content.getBytes());
PatternsFile file = new PatternsFile(inputStream);

Pattern classMatchingPattern = Pattern.compile(file.getClassMatchingPattern());
System.out.println("Class matching pattern = " + classMatchingPattern);
Assert.assertTrue(classMatchingPattern.matcher("com.develorium.metracer.TestA").find());
Assert.assertTrue(classMatchingPattern.matcher("com.develorium.metracer.TestB").find());
Assert.assertTrue(classMatchingPattern.matcher("zzz.com.develorium.metracer.TestA.zzz").find());
Assert.assertTrue(classMatchingPattern.matcher("com.develorium.metracer.TestC$1").find());
Assert.assertTrue(classMatchingPattern.matcher("com.develorium.metracer.TestD_DD").find());
Assert.assertFalse(classMatchingPattern.matcher("com.develorium.").find());
Assert.assertFalse(classMatchingPattern.matcher("com.develorium.metracer.TestC").find());
Assert.assertFalse(classMatchingPattern.matcher("java.lang.String").find());

Pattern methodMatchingPattern = Pattern.compile(file.getMethodMatchingPattern());
System.out.println("Method matching pattern = " + methodMatchingPattern);
Assert.assertTrue(methodMatchingPattern.matcher("com.develorium.metracer.TestA::method1").find());
Assert.assertTrue(methodMatchingPattern.matcher("com.develorium.metracer.TestA::method2").find());
Assert.assertTrue(methodMatchingPattern.matcher("com.develorium.metracer.TestA::method3").find());
Assert.assertTrue(methodMatchingPattern.matcher("com.develorium.metracer.TestB::method0").find());
Assert.assertTrue(methodMatchingPattern.matcher("zzz.com.develorium.metracer.TestB::method0___").find());
Assert.assertTrue(methodMatchingPattern.matcher("com.develorium.metracer.TestC$1::method2").find());
Assert.assertTrue(methodMatchingPattern.matcher("com.develorium.metracer.TestD_DD::m_ethod").find());
Assert.assertFalse(methodMatchingPattern.matcher("com.develorium.metracer.TestA::methodX").find());
Assert.assertFalse(methodMatchingPattern.matcher("com.develorium.metracer.TestB::method2").find());
Assert.assertFalse(methodMatchingPattern.matcher("java.lang.String::substring").find());
}

@Test
public void testLoadingOfDups() throws IOException {
String content =
"com.develorium.metracer.TestA::method1\n" +
"com.develorium.metracer.TestA::method1\n" +
"com.develorium.metracer.TestA::method1\n";
ByteArrayInputStream inputStream = new ByteArrayInputStream(content.getBytes());
PatternsFile file = new PatternsFile(inputStream);

String classMatchingPattern = file.getClassMatchingPattern();
System.out.println("Class matching pattern = " + classMatchingPattern);
Assert.assertFalse(classMatchingPattern.contains("|"));

String methodMatchingPattern = file.getMethodMatchingPattern();
System.out.println("Method matching pattern = " + methodMatchingPattern);
Assert.assertFalse(methodMatchingPattern.contains("|"));
}

@Test
public void testEmptyLoading() throws IOException {
String content =
"# Ignored comment\n" +
"# Another ignored comment\n" +
"\n";
ByteArrayInputStream inputStream = new ByteArrayInputStream(content.getBytes());
PatternsFile file = new PatternsFile(inputStream);
Assert.assertTrue(file.getClassMatchingPattern() == null);
Assert.assertTrue(file.getMethodMatchingPattern() == null);
}

@Test
public void testLoadingOfBadPatterns() throws IOException {
String content =
"com.develorium.metracer.TestA\n" +
"methodName\n" +
"java.lang.String:unknown\n" +
"::methodName\n" +
"ClassName::\n" +
"::\n" +
"com.develorium.metracer.TestA : : methodName\n" +
"com.develorium.metracer.TestA: :methodName\n" +
"com.develorium.metracer.TestA :: methodName\n";

for(String contentLine : content.split("\n")) {
try {
ByteArrayInputStream inputStream = new ByteArrayInputStream(contentLine.getBytes());
PatternsFile file = new PatternsFile(inputStream);
Assert.fail();
} catch(RuntimeException e) {
}
}
}

@Test
public void testConsumingOfPatterns() {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
PatternsFile file = new PatternsFile(outputStream);
file.consumePatterns("com.develorium.metracer.Test::method", "Some context");
Assert.assertTrue(outputStream.toString().contains("com.develorium.metracer.Test::method"));
}
}

0 comments on commit bdcb0e7

Please sign in to comment.