/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.openejb.config.typed.util;
import org.apache.openejb.config.provider.ProviderManager;
import org.apache.openejb.config.provider.ServiceJarXmlLoader;
import org.apache.openejb.config.sys.Resource;
import org.apache.openejb.config.sys.ServiceProvider;
import org.apache.openejb.loader.IO;
import org.apache.openejb.util.Duration;
import org.apache.openejb.util.Join;
import org.apache.openejb.util.Strings;
import java.io.File;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.URI;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @version $Rev$ $Date$
*/
public class ProviderGenerator extends Resource {
public static void main(String[] args) throws Exception {
final ProviderManager manager = new ProviderManager(new ServiceJarXmlLoader());
final Set<String> seen = new HashSet<String>();
final List<ServiceProvider> providers = manager.load("org.apache.openejb");
for (ServiceProvider provider : providers) {
final List<String> types = provider.getTypes();
final String name = guessBuilder(types);
final String builder = name + "Builder";
if (seen.contains(builder)) continue;
seen.add(builder);
final String service = provider.getService();
final File file = new File("/Users/dblevins/work/all/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/config/typed/" + builder + ".java");
final OutputStream write = IO.write(file);
final PrintStream out = new PrintStream(write);
out.println("/*\n" +
" * Licensed to the Apache Software Foundation (ASF) under one or more\n" +
" * contributor license agreements. See the NOTICE file distributed with\n" +
" * this work for additional information regarding copyright ownership.\n" +
" * The ASF licenses this file to You under the Apache License, Version 2.0\n" +
" * (the \"License\"); you may not use this file except in compliance with\n" +
" * the License. You may obtain a copy of the License at\n" +
" *\n" +
" * http://www.apache.org/licenses/LICENSE-2.0\n" +
" *\n" +
" * Unless required by applicable law or agreed to in writing, software\n" +
" * distributed under the License is distributed on an \"AS IS\" BASIS,\n" +
" * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" +
" * See the License for the specific language governing permissions and\n" +
" * limitations under the License.\n" +
" */");
out.println("package org.apache.openejb.config.typed;");
out.println();
out.println("import org.apache.openejb.config.typed.util.*;");
out.println("import org.apache.openejb.config.sys.*;");
out.println("import javax.xml.bind.annotation.*;");
out.println("import " + Duration.class.getName() + ";");
out.println("import java.util.*;");
out.println("import java.util.concurrent.*;");
out.println("import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;");
out.println();
out.println(template(
"@XmlAccessorType(XmlAccessType.FIELD)\n" +
"@XmlRootElement(name = \"${name}\")\n" +
"public class ${builder} extends ${service} {\n"
)
.apply(
"builder", builder,
"service", service,
"name", name
)
);
// Fields
for (Map.Entry<Object, Object> entry : provider.getProperties().entrySet()) {
final String key = Strings.lcfirst(entry.getKey().toString());
final String value = entry.getValue().toString();
final String type = guessType(key, value);
if (Duration.class.getName().endsWith(type)) {
out.println(" @XmlJavaTypeAdapter(DurationAdapter.class)");
}
out.println(
template(
" @XmlAttribute\n" +
" private ${type} ${key} = ${value};"
).apply(
"builder", builder,
"key", key,
"value", asValue(type, value),
"type", type
)
);
}
out.println();
// Constructor
out.println(template(
" public ${builder}() {\n" +
" setClassName(\"${className}\");\n" +
" setType(\"${type}\");\n" +
" setId(\"${name}\");\n"
)
.apply(
"builder", builder,
"className", provider.getClassName() + "",
"type", types.get(0),
"name", name
)
);
if (provider.getConstructor() != null) {
out.println(template(
" setConstructor(\"${constructor}\");\n")
.apply(
"constructor", fixConstructor(provider)
));
}
if (provider.getFactoryName() != null) {
out.println(template(
" setFactoryName(\"${factoryName}\");\n")
.apply(
"factoryName", provider.getFactoryName()
));
}
out.println(" }\n");
// Setters
out.println(template(
" public ${builder} id(String id) {\n" +
" setId(id);\n" +
" return this;\n" +
" }\n").apply("builder", builder)
);
for (Map.Entry<Object, Object> entry : provider.getProperties().entrySet()) {
final String key = Strings.lcfirst(entry.getKey().toString());
final String Key = Strings.ucfirst(key);
final String value = entry.getValue().toString();
final String type = guessType(key, value);
// builder method
out.println(template(
" public ${builder} with${Key}(${type} ${key}) {\n" +
" this.${key} = ${key};\n" +
" return this;\n" +
" }\n")
.apply(
"builder", builder,
"key", key,
"Key", Key,
"value", value,
"type", type
)
);
// setter
out.println(template(
" public void set${Key}(${type} ${key}) {\n" +
" this.${key} = ${key};\n" +
" }\n")
.apply(
"key", key,
"Key", Key,
"value", value,
"type", type
)
);
// getter
out.println(template(
" public ${type} get${Key}() {\n" +
" return ${key};\n" +
" }\n")
.apply(
"key", key,
"Key", Key,
"value", value,
"type", type
)
);
if (Duration.class.getName().equals(type)) {
out.println(template(
" public ${builder} with${Key}(long time, TimeUnit unit) {\n" +
" return with${Key}(new Duration(time, unit));\n" +
" }\n")
.apply(
"builder", builder,
"key", key,
"Key", Key,
"value", value,
"type", type
)
);
out.println(template(
" public void set${Key}(long time, TimeUnit unit) {\n" +
" set${Key}(new Duration(time, unit));\n" +
" }\n")
.apply(
"key", key,
"Key", Key,
"value", value,
"type", type
)
);
}
final String s = key.toLowerCase();
if ("long".equals(type) && s.contains("time")) {
TimeUnit unit = null;
if (s.endsWith("millis")) {
unit = TimeUnit.MILLISECONDS;
} else if (s.endsWith("milliseconds")) {
unit = TimeUnit.MILLISECONDS;
} else if (s.endsWith("seconds")) {
unit = TimeUnit.SECONDS;
} else if (s.endsWith("minutes")) {
unit = TimeUnit.MINUTES;
} else if (s.endsWith("hours")) {
unit = TimeUnit.HOURS;
}
if (unit == null) continue;
final Pattern pattern = Pattern.compile("(millis(econds)?|seconds|minutes|hours)", Pattern.CASE_INSENSITIVE);
final String key2 = pattern.matcher(key).replaceAll("");
final String Key2 = pattern.matcher(Key).replaceAll("");
out.println(template(
" public ${builder} with${Key2}(long time, TimeUnit unit) {\n" +
" return with${Key}(TimeUnit.${unit}.convert(time, unit));\n" +
" }\n")
.apply(
"builder", builder,
"key2", key2,
"Key2", Key2,
"key", key,
"Key", Key,
"value", value,
"unit", unit.name(),
"type", type
)
);
out.println(template(
" public void set${Key2}(long time, TimeUnit unit) {\n" +
" set${Key}(TimeUnit.${unit}.convert(time, unit));\n" +
" }\n")
.apply(
"key2", key2,
"Key2", Key2,
"key", key,
"Key", Key,
"value", value,
"unit", unit.name(),
"type", type
)
);
}
}
out.println(
" public Properties getProperties() {\n" +
" return Builders.getProperties(this);\n" +
" }\n"
);
out.println("}");
out.flush();
out.close();
}
}
private static String fixConstructor(ServiceProvider provider) {
final String s = provider.getConstructor() + "";
final String[] split = s.split(" *, *");
for (int i = 0; i < split.length; i++) {
split[i] = Strings.lcfirst(split[i]);
}
return Join.join(", ", split);
}
private static String asValue(String type, String value) {
if ("".equals(value)) return "null";
if ("String".equals(type)) {
return "\"" + value + "\"";
}
if (URI.class.getName().equals(type)) {
return URI.class.getName() + ".create(\"" + value + "\")";
}
if (Duration.class.getName().equals(type)) {
return Duration.class.getName() + ".parse(\"" + value + "\")";
}
return value;
}
private static String guessBuilder(List<String> types) {
String s = types.get(0);
if ("STATEFUL".equals(s)) return "StatefulContainer";
if ("SINGLETON".equals(s)) return "SingletonContainer";
if ("MANAGED".equals(s)) return "ManagedContainer";
if ("STATELESS".equals(s)) return "StatelessContainer";
if ("MESSAGE".equals(s)) return "MessageDrivenContainer";
if ("BMP_ENTITY".equals(s)) return "BmpEntityContainer";
if ("CMP_ENTITY".equals(s)) return "CmpEntityContainer";
if ("javax.jms.ConnectionFactory".equals(s)) return "JmsConnectionFactory";
if ("javax.mail.Session".equals(s)) return "JavaMailSession";
s = s.replaceAll(".*\\.", "");
return s;
}
private static String guessType(String key, String value) {
if (value.equals("true") || value.equals("false")) return "boolean";
if (key.toLowerCase().endsWith("timeout")) {
return Duration.class.getName();
}
if (value.matches("-?[0-9]+ +(m|h|s|M|H|S)[^ ]*")) {
return Duration.class.getName();
}
if (key.toLowerCase().contains("time")) {
try {
Long.parseLong(value);
return "long";
} catch (NumberFormatException e) {
}
}
try {
Integer.parseInt(value);
return "int";
} catch (NumberFormatException e) {
}
if (key.toLowerCase().endsWith("url")) {
return URI.class.getName();
}
if (key.toLowerCase().endsWith("uri")) {
return URI.class.getName();
}
return "String";
}
public static Template template(String template) {
return new Template(template);
}
public static class Template {
public static final Pattern PATTERN = Pattern.compile("(\\$\\{)((\\.|\\w)+)(})");
private final String template;
public Template(String template) {
this.template = template;
}
public String apply(String... args) {
final Map<String, String> map = new HashMap<String, String>();
for (int i = 0; i < args.length; i += 2) {
String key = args[i];
String value = args[i + 1];
map.put(key, value);
}
return apply(map);
}
public String apply(Map<String, String> map) {
Matcher matcher = PATTERN.matcher(template);
StringBuffer buf = new StringBuffer();
while (matcher.find()) {
String key = matcher.group(2);
if (key == null) throw new IllegalStateException("Key is null. Template '" + template + "'");
String value = map.get(key);
if (key.toLowerCase().endsWith(".lc")) {
value = map.get(key.substring(0, key.length() - 3)).toLowerCase();
} else if (key.toLowerCase().endsWith(".uc")) {
value = map.get(key.substring(0, key.length() - 3)).toUpperCase();
} else if (key.toLowerCase().endsWith(".cc")) {
value = Strings.camelCase(map.get(key.substring(0, key.length() - 3)));
}
if (value == null) throw new IllegalStateException("Value is null for key '" + key + "'. Template '" + template + "'. Keys: " + Join.join(", ", map.keySet()));
matcher.appendReplacement(buf, value);
}
matcher.appendTail(buf);
return buf.toString();
}
}
}