Skip to content

Commit

Permalink
Merge pull request #2 from openrewrite/was-to-liberty-recipes
Browse files Browse the repository at this point in the history
7 added tWAS to liberty recipes
  • Loading branch information
cjobinabo authored Aug 11, 2023
2 parents 1e84a4c + 24b8838 commit e662031
Show file tree
Hide file tree
Showing 17 changed files with 1,911 additions and 19 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,6 @@ gradle-app.setting
.classpath

.idea/
out/
out/
bin/
.vscode/
3 changes: 2 additions & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ plugins {
}

group = "org.openrewrite.recipe"
description = "Open Liberty Migration"
description = "Recipes to migrate to the IBM WebSphere Liberty. Automatically."

val rewriteVersion = rewriteRecipe.rewriteVersion.get()
dependencies {
Expand All @@ -12,6 +12,7 @@ dependencies {
implementation("org.openrewrite:rewrite-java")
implementation("org.openrewrite.recipe:rewrite-java-dependencies")
implementation("org.openrewrite.recipe:rewrite-migrate-java")
implementation("org.openrewrite.recipe:rewrite-static-analysis")

testImplementation("org.openrewrite:rewrite-java-17")
testImplementation("org.openrewrite:rewrite-test")
Expand Down
189 changes: 189 additions & 0 deletions src/main/java/org/openrewrite/java/liberty/ChangeMethodInvocation.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/*
* Copyright 2023 the original author or authors.
* <p>
* 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
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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 org.openrewrite.java.liberty;

import lombok.EqualsAndHashCode;
import lombok.Value;

import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.openrewrite.*;
import org.openrewrite.internal.lang.NonNull;
import org.openrewrite.internal.lang.Nullable;
import org.openrewrite.java.JavaTemplate;
import org.openrewrite.java.JavaVisitor;
import org.openrewrite.java.MethodMatcher;
import org.openrewrite.java.tree.*;
import org.openrewrite.java.tree.JavaType.FullyQualified;
import org.openrewrite.marker.Markers;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

/*
Development in this class is not complete
*/
@Value
@EqualsAndHashCode(callSuper = true)
public class ChangeMethodInvocation extends Recipe {

@Option(displayName = "Method pattern",
description = "A method pattern that is used to find matching method invocations.",
example = "org.mockito.Matchers anyVararg()")
@NonNull
String methodPattern;

@Option(displayName = "New method name",
description = "The method name that will replace the existing name.",
example = "org.mockito.Matchers any()")
@NonNull
String newMethodPattern;

@Option(displayName = "Perform static methd call",
description = "When set to `true` the method invocation will be performed statically.",
example = "true",
required = false)
@Nullable
Boolean performStaticCall;

@JsonCreator
public ChangeMethodInvocation(@NonNull @JsonProperty("methodPattern") String methodPattern,
@NonNull @JsonProperty("newMethodPattern") String newMethodPattern, @Nullable @JsonProperty("performStaticCall") Boolean performStaticCall) {
this.methodPattern = methodPattern;
this.newMethodPattern = newMethodPattern;
this.performStaticCall = performStaticCall;
}


@Override
public String getDisplayName() {
return "Change method invocation";
}

@Override
public String getDescription() {
return "Rename a method invocation.";
}

@Override
public boolean causesAnotherCycle() {
return true;
}

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return new ChangeMethodInvocationVisitor(new MethodMatcher(methodPattern, false), newMethodPattern);
}

private class ChangeMethodInvocationVisitor extends JavaVisitor<ExecutionContext> {
private final MethodMatcher methodMatcher;
private MethodMatcher methodReplacmentMatcher;
private String oldMethodType;

private String newMethodType;
private String newMethodOwnerName;
private String newMethodName;
private String newMethodsArgsStr;

Pattern methodPatternMatcher = Pattern.compile("([^\\s]+)\\s+([a-zA-Z0-9]+)\\((.*)\\)");

private ChangeMethodInvocationVisitor(MethodMatcher methodMatcher, String newMethodPattern) {
this.methodMatcher = methodMatcher;
this.oldMethodType = methodMatcher.getTargetTypePattern().pattern().replace("[.$]", ".");

if (newMethodPattern != null) {
Matcher m = methodPatternMatcher.matcher(newMethodPattern);
if (m.find()) {
this.newMethodType = m.group(1);
if (this.newMethodType != null) {
String[] parts = this.newMethodType.split("\\.");
this.newMethodOwnerName = parts[parts.length - 1];
}

this.newMethodName = m.group(2);
this.newMethodsArgsStr = m.group(3);
if (this.newMethodsArgsStr != null) {
StringBuilder newArgs = new StringBuilder();
int argSize = newMethodsArgsStr.split(",").length;
for (int i = 1; i <= argSize; i++) {
newArgs.append("*");
if (i < argSize) {
newArgs.append(",");
}
}
this.methodReplacmentMatcher = new MethodMatcher(newMethodPattern.replace(this.newMethodsArgsStr, newArgs), false);
} else {
this.newMethodsArgsStr = "";
this.methodReplacmentMatcher = new MethodMatcher(newMethodPattern, false);
}
}
}
}

@Override
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ctx) {
J.MethodInvocation m = method;

if (methodReplacmentMatcher != null && methodMatcher.matches(method) && !methodReplacmentMatcher.matches(method)) {
if (performStaticCall) {
String temp = newMethodType + "." + newMethodName + "(" + newMethodsArgsStr + ");";
JavaTemplate addArgTemplate = JavaTemplate.builder(temp).build();
J.MethodInvocation qualifiedInvocation = addArgTemplate.apply(getCursor(), m.getCoordinates().replace());

temp = newMethodOwnerName + "." + newMethodName + "(" + newMethodsArgsStr + ");";
addArgTemplate = JavaTemplate.builder(temp).build();
J.MethodInvocation simpleInvocation = addArgTemplate.apply(getCursor(), m.getCoordinates().replace());

m = simpleInvocation.withMethodType(qualifiedInvocation.getMethodType());
m = m.withSelect(m.getSelect().withType(qualifiedInvocation.getSelect().getType()));

maybeAddImport(m.getMethodType().getDeclaringType().getFullyQualifiedName(), false);
maybeRemoveImport(oldMethodType);
} else {
// This block of code is not complete
JavaType.Method type = m.getMethodType();
if (type != null) {
type = type.withName(newMethodName);
FullyQualified declaringType = type.getDeclaringType();
String previousMethodType = declaringType.getFullyQualifiedName();
declaringType = declaringType.withFullyQualifiedName(newMethodType);
type = type.withDeclaringType(declaringType);

//add new import and remove old if no longer used
maybeAddImport(newMethodType);
maybeRemoveImport(previousMethodType);
}
m = m.withName(m.getName().withSimpleName(newMethodName))
.withMethodType(type);

if (this.newMethodsArgsStr == null) {
// clear arguments
List<Expression> methodArgs = Collections.singletonList(new J.Empty(Tree.randomId(), Space.EMPTY, Markers.EMPTY));
m = m.withArguments(methodArgs);
} else {
// override arguments
JavaTemplate addArgTemplate = JavaTemplate.builder(newMethodsArgsStr).build();
m = addArgTemplate.apply(getCursor(), m.getCoordinates().replaceArguments());
}
}
}
return m;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright 2023 the original author or authors.
* <p>
* 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
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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 org.openrewrite.java.liberty;

import lombok.EqualsAndHashCode;
import lombok.Value;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.openrewrite.ExecutionContext;
import org.openrewrite.Option;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.internal.lang.NonNull;
import org.openrewrite.java.JavaIsoVisitor;
import org.openrewrite.java.tree.*;

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonProperty;

@Value
@EqualsAndHashCode(callSuper = true)
public class ChangeStringLiteral extends Recipe {

@Option(displayName = "Value pattern",
description = "A pattern that is used to find matching string literal.",
example = "java:(.*)")
@NonNull
String valuePattern;

@Option(displayName = "New value template",
description = "The template that will replace the existing value.",
example = "org:$1")
@NonNull
String newValueTemplate;

@JsonCreator
public ChangeStringLiteral(@NonNull @JsonProperty("valuePattern") String valuePattern, @NonNull @JsonProperty("newValueTemplate") String newValueTemplate) {
this.valuePattern = valuePattern;
this.newValueTemplate = newValueTemplate;
}


@Override
public String getDisplayName() {
return "Change string literal";
}

@Override
public String getDescription() {
return "Changes the value of a string literal.";
}

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return new ChangeStringLiteralVisitor<>(Pattern.compile(valuePattern), newValueTemplate);
}

@Value
@EqualsAndHashCode(callSuper = true)
public class ChangeStringLiteralVisitor<P> extends JavaIsoVisitor<P> {
Pattern valuePattern;
String newValueTemplate;

@Override
public J.Literal visitLiteral(J.Literal literal, P p) {
String literalValue = literal.getValue().toString();
Matcher m = valuePattern.matcher(literalValue);
if (m.find()) {
literalValue = m.replaceFirst(newValueTemplate);
literal = literal.withValue(literalValue).withValueSource(literalValue);
}
return literal;
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* Copyright 2023 the original author or authors.
* <p>
* 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
* <p>
* https://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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 org.openrewrite.java.liberty;

import java.util.function.Supplier;

import org.openrewrite.internal.lang.Nullable;
import org.openrewrite.ExecutionContext;
import org.openrewrite.Recipe;
import org.openrewrite.TreeVisitor;
import org.openrewrite.java.JavaVisitor;
import org.openrewrite.java.MethodMatcher;
import org.openrewrite.java.tree.Expression;
import org.openrewrite.java.tree.J;
import org.openrewrite.java.tree.MethodCall;

public class RemoveWas2LibertyNonPortableJndiLookup extends Recipe {

@Override
public String getDisplayName() {
return "Removes invalid JNDI properties";
}

@Override
public String getDescription() {
return "Remove the use of invalid JNDI properties from Hashtable.";
}

@Override
public TreeVisitor<?, ExecutionContext> getVisitor() {
return new MethodInvocationVisitor();
}

private class MethodInvocationVisitor extends JavaVisitor<ExecutionContext> {
MethodMatcher methodMatcher = new MethodMatcher("java.util.Hashtable put(java.lang.Object, java.lang.Object)", false);

@SuppressWarnings("NullableProblems")
@Nullable
@Override
public J.MethodInvocation visitMethodInvocation(J.MethodInvocation method, ExecutionContext ec) {
return visitMethodCall(method);
}

@Nullable
private <M extends MethodCall> M visitMethodCall(M methodCall) {
if (!methodMatcher.matches(methodCall)) {
return methodCall;
}
J.Block parentBlock = getCursor().firstEnclosing(J.Block.class);
//noinspection SuspiciousMethodCalls
if (parentBlock != null && !parentBlock.getStatements().contains(methodCall)) {
return methodCall;
}
// Remove the method invocation when the argumentMatcherPredicate is true for all arguments
Expression firstArg = methodCall.getArguments().get(0);
if (firstArg instanceof J.Literal) {
J.Literal literalExp = (J.Literal) firstArg;
Object value = literalExp.getValue();
if (!value.equals("java.naming.factory.initial") && !value.equals("java.naming.provider.url")) {
return methodCall;
}
} else {
return methodCall;
}

if (methodCall.getMethodType() != null) {
maybeRemoveImport(methodCall.getMethodType().getDeclaringType());
}
return null;
}
}

}
Loading

0 comments on commit e662031

Please sign in to comment.