You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2017/02/03 19:31:41 UTC
[3/7] camel git commit: CAMEL-10774: Generate other json schema for
Camel artifacts which is not a component, dataformat or language
CAMEL-10774: Generate other json schema for Camel artifacts which is not a component, dataformat or language
Project: http://git-wip-us.apache.org/repos/asf/camel/repo
Commit: http://git-wip-us.apache.org/repos/asf/camel/commit/490d49e0
Tree: http://git-wip-us.apache.org/repos/asf/camel/tree/490d49e0
Diff: http://git-wip-us.apache.org/repos/asf/camel/diff/490d49e0
Branch: refs/heads/master
Commit: 490d49e001dec0e8fdcba7803f4a89d9c7f717fe
Parents: 41200e2
Author: Claus Ibsen <da...@apache.org>
Authored: Fri Feb 3 18:03:36 2017 +0100
Committer: Claus Ibsen <da...@apache.org>
Committed: Fri Feb 3 20:31:28 2017 +0100
----------------------------------------------------------------------
components/camel-eclipse/pom.xml | 16 +-
.../camel/maven/packaging/PackageOtherMojo.java | 187 ++++++++++++++-
.../maven/packaging/PrepareCatalogMojo.java | 235 ++++++++++++++++++-
.../maven/packaging/PrepareComponentMojo.java | 2 +-
.../camel/maven/packaging/StringHelper.java | 29 +++
5 files changed, 454 insertions(+), 15 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/camel/blob/490d49e0/components/camel-eclipse/pom.xml
----------------------------------------------------------------------
diff --git a/components/camel-eclipse/pom.xml b/components/camel-eclipse/pom.xml
index 85146da..4a86c18 100644
--- a/components/camel-eclipse/pom.xml
+++ b/components/camel-eclipse/pom.xml
@@ -30,12 +30,16 @@
<description>Camel Eclipse support</description>
<properties>
- <camel.osgi.export.pkg>org.apache.camel.component.eclipse.*</camel.osgi.export.pkg>
- <camel.osgi.import.pkg>
- !org.apache.camel.component.eclipse.*,
- org.apache.camel.*;${camel.osgi.import.camel.version},
- org.eclipse.core.runtime;common=!
- </camel.osgi.import.pkg>
+ <!-- use by camel-catalog -->
+ <firstVersion>2.3.0</firstVersion>
+ <label>tooling</label>
+
+ <camel.osgi.export.pkg>org.apache.camel.component.eclipse.*</camel.osgi.export.pkg>
+ <camel.osgi.import.pkg>
+ !org.apache.camel.component.eclipse.*,
+ org.apache.camel.*;${camel.osgi.import.camel.version},
+ org.eclipse.core.runtime;common=!
+ </camel.osgi.import.pkg>
</properties>
<dependencies>
http://git-wip-us.apache.org/repos/asf/camel/blob/490d49e0/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageOtherMojo.java
----------------------------------------------------------------------
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageOtherMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageOtherMojo.java
index f061947..87e99ed 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageOtherMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PackageOtherMojo.java
@@ -33,6 +33,8 @@ import org.apache.maven.project.MavenProject;
import org.apache.maven.project.MavenProjectHelper;
import org.sonatype.plexus.build.incremental.BuildContext;
+import static org.apache.camel.maven.packaging.StringHelper.camelDashToTitle;
+
/**
* Analyses the Camel plugins in a project and generates extra descriptor information for easier auto-discovery in Camel.
*
@@ -57,6 +59,13 @@ public class PackageOtherMojo extends AbstractMojo {
protected File otherOutDir;
/**
+ * The output directory for generated languages file
+ *
+ * @parameter default-value="${project.build.directory}/classes"
+ */
+ protected File schemaOutDir;
+
+ /**
* Maven ProjectHelper.
*
* @component
@@ -81,11 +90,11 @@ public class PackageOtherMojo extends AbstractMojo {
* @throws MojoFailureException something bad happened...
*/
public void execute() throws MojoExecutionException, MojoFailureException {
- prepareOthers(getLog(), project, projectHelper, otherOutDir, buildContext);
+ prepareOthers(getLog(), project, projectHelper, otherOutDir, schemaOutDir, buildContext);
}
- public static void prepareOthers(Log log, MavenProject project, MavenProjectHelper projectHelper,
- File otherOutDir, BuildContext buildContext) throws MojoExecutionException {
+ public static void prepareOthers(Log log, MavenProject project, MavenProjectHelper projectHelper, File otherOutDir,
+ File schemaOutDir, BuildContext buildContext) throws MojoExecutionException {
// are there any components, data formats or languages?
for (Resource r : project.getBuild().getResources()) {
@@ -121,9 +130,57 @@ public class PackageOtherMojo extends AbstractMojo {
return;
}
+ String name = project.getArtifactId();
+ // strip leading camel-
+ if (name.startsWith("camel-")) {
+ name = name.substring(6);
+ }
+
+ try {
+ // create json model
+ OtherModel otherModel = new OtherModel();
+ otherModel.setName(name);
+ otherModel.setGroupId(project.getGroupId());
+ otherModel.setArtifactId(project.getArtifactId());
+ otherModel.setVersion(project.getVersion());
+ otherModel.setDescription(project.getDescription());
+ if (project.getName() != null && project.getName().contains("(deprecated)")) {
+ otherModel.setDeprecated("true");
+ } else {
+ otherModel.setDeprecated("false");
+ }
+ otherModel.setFirstVersion(project.getProperties().getProperty("firstVersion"));
+ otherModel.setLabel(project.getProperties().getProperty("label"));
+ String title = project.getProperties().getProperty("title");
+ if (title == null) {
+ title = camelDashToTitle(name);
+ }
+ otherModel.setTitle(title);
+
+ log.debug("Model " + otherModel);
+
+ // write this to the directory
+ File dir = schemaOutDir;
+ dir.mkdirs();
+
+ File out = new File(dir, name + ".json");
+ OutputStream fos = buildContext.newFileOutputStream(out);
+ String json = createJsonSchema(otherModel);
+ fos.write(json.getBytes());
+ fos.close();
+
+ buildContext.refresh(out);
+
+ log.debug("Generated " + out + " containing JSon schema for " + name + " other");
+ } catch (Exception e) {
+ throw new MojoExecutionException("Error loading language model from camel-core. Reason: " + e, e);
+ }
+
+ // now create properties file
File camelMetaDir = new File(otherOutDir, "META-INF/services/org/apache/camel/");
Properties properties = new Properties();
+ properties.put("name", name);
properties.put("groupId", project.getGroupId());
properties.put("artifactId", project.getArtifactId());
properties.put("version", project.getVersion());
@@ -167,4 +224,128 @@ public class PackageOtherMojo extends AbstractMojo {
}
}
+ private static String createJsonSchema(OtherModel otherModel) {
+ StringBuilder buffer = new StringBuilder("{");
+ // language model
+ buffer.append("\n \"other\": {");
+ buffer.append("\n \"name\": \"").append(otherModel.getName()).append("\",");
+ buffer.append("\n \"kind\": \"").append("other").append("\",");
+ if (otherModel.getTitle() != null) {
+ buffer.append("\n \"title\": \"").append(otherModel.getTitle()).append("\",");
+ }
+ if (otherModel.getDescription() != null) {
+ buffer.append("\n \"description\": \"").append(otherModel.getDescription()).append("\",");
+ }
+ buffer.append("\n \"deprecated\": \"").append(otherModel.getDeprecated()).append("\",");
+ if (otherModel.getFirstVersion() != null) {
+ buffer.append("\n \"firstVersion\": \"").append(otherModel.getFirstVersion()).append("\",");
+ }
+ if (otherModel.getLabel() != null) {
+ buffer.append("\n \"label\": \"").append(otherModel.getLabel()).append("\",");
+ }
+ buffer.append("\n \"groupId\": \"").append(otherModel.getGroupId()).append("\",");
+ buffer.append("\n \"artifactId\": \"").append(otherModel.getArtifactId()).append("\",");
+ buffer.append("\n \"version\": \"").append(otherModel.getVersion()).append("\"");
+ buffer.append("\n }");
+ buffer.append("\n}");
+ return buffer.toString();
+ }
+
+ private static class OtherModel {
+ private String name;
+ private String title;
+ private String description;
+ private String deprecated;
+ private String firstVersion;
+ private String label;
+ private String groupId;
+ private String artifactId;
+ private String version;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ public String getTitle() {
+ return title;
+ }
+
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ public String getDescription() {
+ return description;
+ }
+
+ public void setDescription(String description) {
+ this.description = description;
+ }
+
+ public String getDeprecated() {
+ return deprecated;
+ }
+
+ public void setDeprecated(String deprecated) {
+ this.deprecated = deprecated;
+ }
+
+ public String getFirstVersion() {
+ return firstVersion;
+ }
+
+ public void setFirstVersion(String firstVersion) {
+ this.firstVersion = firstVersion;
+ }
+
+ public String getLabel() {
+ return label;
+ }
+
+ public void setLabel(String label) {
+ this.label = label;
+ }
+
+ public String getGroupId() {
+ return groupId;
+ }
+
+ public void setGroupId(String groupId) {
+ this.groupId = groupId;
+ }
+
+ public String getArtifactId() {
+ return artifactId;
+ }
+
+ public void setArtifactId(String artifactId) {
+ this.artifactId = artifactId;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public void setVersion(String version) {
+ this.version = version;
+ }
+
+ @Override
+ public String toString() {
+ return "OtherModel["
+ + "name='" + name + '\''
+ + ", title='" + title + '\''
+ + ", description='" + description + '\''
+ + ", label='" + label + '\''
+ + ", groupId='" + groupId + '\''
+ + ", artifactId='" + artifactId + '\''
+ + ", version='" + version + '\''
+ + ']';
+ }
+ }
+
}
http://git-wip-us.apache.org/repos/asf/camel/blob/490d49e0/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCatalogMojo.java
----------------------------------------------------------------------
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCatalogMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCatalogMojo.java
index 62786ff..2728c57 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCatalogMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareCatalogMojo.java
@@ -105,6 +105,13 @@ public class PrepareCatalogMojo extends AbstractMojo {
protected File languagesOutDir;
/**
+ * The output directory for others catalog
+ *
+ * @parameter default-value="${project.build.directory}/classes/org/apache/camel/catalog/others"
+ */
+ protected File othersOutDir;
+
+ /**
* The output directory for documents catalog
*
* @parameter default-value="${project.build.directory}/classes/org/apache/camel/catalog/docs"
@@ -194,7 +201,8 @@ public class PrepareCatalogMojo extends AbstractMojo {
Set<String> components = executeComponents();
Set<String> dataformats = executeDataFormats();
Set<String> languages = executeLanguages();
- executeDocuments(components, dataformats, languages);
+ Set<String> others = executeOthers();
+ executeDocuments(components, dataformats, languages, others);
executeArchetypes();
executeXmlSchemas();
}
@@ -763,6 +771,135 @@ public class PrepareCatalogMojo extends AbstractMojo {
return answer;
}
+ private Set<String> executeOthers() throws MojoFailureException {
+ getLog().info("Copying all Camel other json descriptors");
+
+ // lets use sorted set/maps
+ Set<File> jsonFiles = new TreeSet<File>();
+ Set<File> duplicateJsonFiles = new TreeSet<File>();
+ Set<File> otherFiles = new TreeSet<File>();
+ Map<String, Set<String>> usedLabels = new TreeMap<String, Set<String>>();
+ Set<File> missingFirstVersions = new TreeSet<File>();
+
+ // find all others from the components directory
+ if (componentsDir != null && componentsDir.isDirectory()) {
+ File[] others = componentsDir.listFiles();
+ if (others != null) {
+ for (File dir : others) {
+
+ // skip these special cases
+ // (camel-jetty is a placeholder, as camel-jetty9 is the actual component)
+ if ("camel-core-osgi".equals(dir.getName())
+ || "camel-core-xml".equals(dir.getName())
+ || "camel-http-common".equals(dir.getName())
+ || "camel-jetty".equals(dir.getName())
+ || "camel-jetty-common".equals(dir.getName())
+ || "camel-linkedin".equals(dir.getName())
+ || "camel-olingo2".equals(dir.getName())
+ || "camel-salesforce".equals(dir.getName())) {
+ continue;
+ }
+
+ if (dir.isDirectory() && !"target".equals(dir.getName())) {
+ File target = new File(dir, "target/classes");
+ findOtherFilesRecursive(target, jsonFiles, otherFiles, new CamelOthersFileFilter());
+ }
+ }
+ }
+ }
+ // nothing in camel-core
+
+ getLog().info("Found " + otherFiles.size() + " other.properties files");
+ getLog().info("Found " + jsonFiles.size() + " other json files");
+
+ // make sure to create out dir
+ othersOutDir.mkdirs();
+
+ for (File file : jsonFiles) {
+ File to = new File(othersOutDir, file.getName());
+ if (to.exists()) {
+ duplicateJsonFiles.add(to);
+ getLog().warn("Duplicate other name detected: " + to);
+ }
+ try {
+ copyFile(file, to);
+ } catch (IOException e) {
+ throw new MojoFailureException("Cannot copy file from " + file + " -> " + to, e);
+ }
+
+ // check if we have a label as we want the other to include labels
+ try {
+ String text = loadText(new FileInputStream(file));
+ String name = asComponentName(file);
+ Matcher matcher = LABEL_PATTERN.matcher(text);
+ // grab the label, and remember it in the used labels
+ if (matcher.find()) {
+ String label = matcher.group(1);
+ String[] labels = label.split(",");
+ for (String s : labels) {
+ Set<String> others = usedLabels.get(s);
+ if (others == null) {
+ others = new TreeSet<String>();
+ usedLabels.put(s, others);
+ }
+ others.add(name);
+ }
+ }
+
+ // detect missing first version
+ List<Map<String, String>> rows = JSonSchemaHelper.parseJsonSchema("other", text, false);
+ String firstVersion = null;
+ for (Map<String, String> row : rows) {
+ if (row.get("firstVersion") != null) {
+ firstVersion = row.get("firstVersion");
+ }
+ }
+ if (firstVersion == null) {
+ missingFirstVersions.add(file);
+ }
+
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+
+ Set<String> answer = new LinkedHashSet<>();
+
+ File all = new File(othersOutDir, "../others.properties");
+ try {
+ FileOutputStream fos = new FileOutputStream(all, false);
+
+ String[] names = othersOutDir.list();
+ List<String> others = new ArrayList<String>();
+ // sort the names
+ for (String name : names) {
+ if (name.endsWith(".json")) {
+ // strip out .json from the name
+ String otherName = name.substring(0, name.length() - 5);
+ others.add(otherName);
+ }
+ }
+
+ Collections.sort(others);
+ for (String name : others) {
+ fos.write(name.getBytes());
+ fos.write("\n".getBytes());
+
+ // remember other name
+ answer.add(name);
+ }
+
+ fos.close();
+
+ } catch (IOException e) {
+ throw new MojoFailureException("Error writing to file " + all);
+ }
+
+ printOthersReport(jsonFiles, duplicateJsonFiles, usedLabels, missingFirstVersions);
+
+ return answer;
+ }
+
protected void executeArchetypes() throws MojoExecutionException, MojoFailureException {
getLog().info("Copying Archetype Catalog");
@@ -807,7 +944,7 @@ public class PrepareCatalogMojo extends AbstractMojo {
}
}
- protected void executeDocuments(Set<String> components, Set<String> dataformats, Set<String> languages) throws MojoExecutionException, MojoFailureException {
+ protected void executeDocuments(Set<String> components, Set<String> dataformats, Set<String> languages, Set<String> others) throws MojoExecutionException, MojoFailureException {
getLog().info("Copying all Camel documents (ascii docs)");
// lets use sorted set/maps
@@ -928,11 +1065,11 @@ public class PrepareCatalogMojo extends AbstractMojo {
printDocumentsReport(adocFiles, duplicateAdocFiles, missingAdocFiles);
- // find out if we have documents for each component / dataformat / languages
- printMissingDocumentsReport(docs, components, dataformats, languages);
+ // find out if we have documents for each component / dataformat / languages / others
+ printMissingDocumentsReport(docs, components, dataformats, languages, others);
}
- private void printMissingDocumentsReport(Set<String> docs, Set<String> components, Set<String> dataformats, Set<String> languages) {
+ private void printMissingDocumentsReport(Set<String> docs, Set<String> components, Set<String> dataformats, Set<String> languages, Set<String> others) {
getLog().info("");
getLog().info("Camel missing documents report");
getLog().info("");
@@ -993,6 +1130,21 @@ public class PrepareCatalogMojo extends AbstractMojo {
}
missing.clear();
+ for (String other : others) {
+ String name = other;
+ if (!docs.contains(name)) {
+ missing.add(name);
+ }
+ }
+ if (!missing.isEmpty()) {
+ getLog().info("");
+ getLog().warn("\tMissing .adoc other documentation : " + missing.size());
+ for (String name : missing) {
+ getLog().warn("\t\t" + name);
+ }
+ }
+ missing.clear();
+
getLog().info("");
getLog().info("================================================================================");
}
@@ -1175,6 +1327,43 @@ public class PrepareCatalogMojo extends AbstractMojo {
getLog().info("================================================================================");
}
+ private void printOthersReport(Set<File> json, Set<File> duplicate, Map<String, Set<String>> usedLabels, Set<File> missingFirstVersions) {
+ getLog().info("================================================================================");
+ getLog().info("");
+ getLog().info("Camel other catalog report");
+ getLog().info("");
+ getLog().info("\tOthers found: " + json.size());
+ for (File file : json) {
+ getLog().info("\t\t" + asComponentName(file));
+ }
+ if (!duplicate.isEmpty()) {
+ getLog().info("");
+ getLog().warn("\tDuplicate other detected: " + duplicate.size());
+ for (File file : duplicate) {
+ getLog().warn("\t\t" + asComponentName(file));
+ }
+ }
+ if (!usedLabels.isEmpty()) {
+ getLog().info("");
+ getLog().info("\tUsed labels: " + usedLabels.size());
+ for (Map.Entry<String, Set<String>> entry : usedLabels.entrySet()) {
+ getLog().info("\t\t" + entry.getKey() + ":");
+ for (String name : entry.getValue()) {
+ getLog().info("\t\t\t" + name);
+ }
+ }
+ }
+ if (!missingFirstVersions.isEmpty()) {
+ getLog().info("");
+ getLog().warn("\tOthers without firstVersion defined: " + missingFirstVersions.size());
+ for (File name : missingFirstVersions) {
+ getLog().warn("\t\t" + name.getName());
+ }
+ }
+ getLog().info("");
+ getLog().info("================================================================================");
+ }
+
private void printDocumentsReport(Set<File> docs, Set<File> duplicate, Set<File> missing) {
getLog().info("================================================================================");
getLog().info("");
@@ -1268,6 +1457,25 @@ public class PrepareCatalogMojo extends AbstractMojo {
}
}
+ private void findOtherFilesRecursive(File dir, Set<File> found, Set<File> others, FileFilter filter) {
+ File[] files = dir.listFiles(filter);
+ if (files != null) {
+ for (File file : files) {
+ // skip files in root dirs as Camel does not store information there but others may do
+ boolean rootDir = "classes".equals(dir.getName()) || "META-INF".equals(dir.getName());
+ boolean jsonFile = rootDir && file.isFile() && file.getName().endsWith(".json");
+ boolean otherFile = !rootDir && file.isFile() && file.getName().equals("other.properties");
+ if (jsonFile) {
+ found.add(file);
+ } else if (otherFile) {
+ others.add(file);
+ } else if (file.isDirectory()) {
+ findOtherFilesRecursive(file, found, others, filter);
+ }
+ }
+ }
+ }
+
private void findAsciiDocFilesRecursive(File dir, Set<File> found, FileFilter filter) {
File[] files = dir.listFiles(filter);
if (files != null) {
@@ -1347,6 +1555,23 @@ public class PrepareCatalogMojo extends AbstractMojo {
}
}
+ private class CamelOthersFileFilter implements FileFilter {
+
+ @Override
+ public boolean accept(File pathname) {
+ if (pathname.isFile() && pathname.getName().endsWith(".json")) {
+ // must be a language json file
+ try {
+ String json = loadText(new FileInputStream(pathname));
+ return json != null && json.contains("\"kind\": \"other\"");
+ } catch (IOException e) {
+ // ignore
+ }
+ }
+ return pathname.isDirectory() || (pathname.isFile() && pathname.getName().equals("other.properties"));
+ }
+ }
+
private class CamelAsciiDocFileFilter implements FileFilter {
@Override
http://git-wip-us.apache.org/repos/asf/camel/blob/490d49e0/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareComponentMojo.java
----------------------------------------------------------------------
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareComponentMojo.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareComponentMojo.java
index 7d5c8ed..5b99b9a 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareComponentMojo.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/PrepareComponentMojo.java
@@ -116,7 +116,7 @@ public class PrepareComponentMojo extends AbstractMojo {
prepareComponent(getLog(), project, projectHelper, componentOutDir, buildContext);
prepareDataFormat(getLog(), project, projectHelper, dataFormatOutDir, schemaOutDir, buildContext);
prepareLanguage(getLog(), project, projectHelper, languageOutDir, schemaOutDir, buildContext);
- prepareOthers(getLog(), project, projectHelper, otherOutDir, buildContext);
+ prepareOthers(getLog(), project, projectHelper, otherOutDir, schemaOutDir, buildContext);
}
}
http://git-wip-us.apache.org/repos/asf/camel/blob/490d49e0/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/StringHelper.java
----------------------------------------------------------------------
diff --git a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/StringHelper.java b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/StringHelper.java
index e17f430..b65ada8 100644
--- a/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/StringHelper.java
+++ b/tooling/maven/camel-package-maven-plugin/src/main/java/org/apache/camel/maven/packaging/StringHelper.java
@@ -58,4 +58,33 @@ public final class StringHelper {
return sb.toString();
}
+ /**
+ * Converts the value to use title style instead of dash cased
+ */
+ public static String camelDashToTitle(String value) {
+ StringBuilder sb = new StringBuilder(value.length());
+ boolean dash = false;
+
+ for (char c : value.toCharArray()) {
+ if ('-' == c) {
+ dash = true;
+ continue;
+ }
+
+ if (dash) {
+ sb.append(' ');
+ sb.append(Character.toUpperCase(c));
+ } else {
+ // upper case first
+ if (sb.length() == 0) {
+ sb.append(Character.toUpperCase(c));
+ } else {
+ sb.append(c);
+ }
+ }
+ dash = false;
+ }
+ return sb.toString();
+ }
+
}