/*
* Copyright 2012 James Moger
*
* 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 org.moxie;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.text.DateFormat;
import java.text.MessageFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.TreeMap;
import org.moxie.Constants.Key;
import org.moxie.maxml.Maxml;
import org.moxie.maxml.MaxmlException;
import org.moxie.maxml.MaxmlMap;
import org.moxie.utils.FileUtils;
import org.moxie.utils.StringUtils;
/**
* Caches Moxie information about an artifact.
*/
public class MoxieData implements Serializable {
private static final long serialVersionUID = 1L;
private static final int currentSolutionVersion = 2;
private final File file;
private final Map<Scope, Set<Dependency>> dependencies;
private int solutionVersion;
private Date lastDownloaded;
private Date lastChecked;
private Date lastUpdated;
private Date lastSolved;
private String origin;
private String groupId;
private String artifactId;
private String version;
private String revision;
private String release;
private String latest;
public MoxieData(File file) {
this.file = file;
this.dependencies = new TreeMap<Scope, Set<Dependency>>();
this.lastDownloaded = new Date(0);
this.lastChecked = new Date(0);
this.lastUpdated = new Date(0);
this.lastSolved = new Date(0);
try {
parse();
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public String toString() {
return "MoxieData (" + file + ")";
}
MoxieData parse() throws IOException, MaxmlException {
MaxmlMap map = new MaxmlMap();
if (file.exists()) {
String content = FileUtils.readContent(file, "\n").trim();
map = Maxml.parse(content);
}
parseDependencies(map, Key.dependencies);
lastDownloaded = parseDate(map, Key.lastDownloaded, lastDownloaded);
lastChecked = parseDate(map, Key.lastChecked, lastChecked);
lastUpdated = parseDate(map, Key.lastUpdated, lastUpdated);
lastSolved = parseDate(map, Key.lastSolved, lastSolved);
origin = map.getString(Key.origin.name(), null);
if ("null".equals(origin)) {
// Moxie <= 0.5.0 workaround
// null origin b/c of .m2/repository copy persisted as "null"
origin = null;
}
solutionVersion = map.getInt("solutionVersion", 0);
return this;
}
Date parseDate(MaxmlMap map, Key key, Date defaultValue) {
String date = map.getString(key.name(), null);
if (!StringUtils.isEmpty(date)) {
try {
Date aDate = getDateFormat().parse(date);
// reset milliseconds to we compare to the second
Calendar c = Calendar.getInstance();
c.setTime(aDate);
c.set(Calendar.MILLISECOND, 0);
return c.getTime();
} catch (ParseException e) {
}
}
return defaultValue;
}
void parseDependencies(MaxmlMap map, Key key) {
if (map.containsKey(key.name())) {
List<?> values = (List<?>) map.get(key.name());
for (Object definition : values) {
if (definition instanceof String) {
String [] fields = definition.toString().split(" ");
Scope solutionScope = Scope.fromString(fields[0]);
int ring = Integer.parseInt(fields[1]);
String def = StringUtils.stripQuotes(fields[2].trim());
Scope dependencyScope;
if (fields.length > 3) {
dependencyScope = Scope.fromString(fields[3]);
} else {
// for backwards-compatibility, even though it is incorrect
dependencyScope = solutionScope;
}
Dependency dep;
if (Scope.system.equals(solutionScope)) {
dep = new SystemDependency(def);
} else {
dep = new Dependency(def);
}
dep.ring = ring;
dep.definedScope = dependencyScope;
addDependency(dep, solutionScope);
} else {
throw new RuntimeException("Illegal dependency " + definition);
}
}
}
}
private void addDependency(Dependency dep, Scope scope) {
if (!dependencies.containsKey(scope)) {
dependencies.put(scope, new LinkedHashSet<Dependency>());
}
dependencies.get(scope).add(dep);
}
public boolean hasScope(Scope scope) {
return dependencies.containsKey(scope);
}
public List<Scope> getScopes() {
return new ArrayList<Scope>(dependencies.keySet());
}
public Set<Dependency> getDependencies(Scope scope) {
return dependencies.get(scope);
}
public void setDependencies(Scope scope, Collection<Dependency> dependencies) {
if (dependencies.size() > 0) {
this.dependencies.put(scope, new LinkedHashSet<Dependency>(dependencies));
} else {
this.dependencies.remove(scope);
}
}
public void setArtifact(Dependency dep) {
this.groupId = dep.groupId;
this.artifactId = dep.artifactId;
this.version = dep.version;
this.revision = dep.revision;
}
public Date getLastDownloaded() {
return lastDownloaded;
}
public void setLastDownloaded(Date date) {
this.lastDownloaded = date;
}
public Date getLastChecked() {
return lastChecked;
}
public void setLastChecked(Date date) {
this.lastChecked = date;
}
public Date getLastUpdated() {
return lastUpdated;
}
public void setLastUpdated(Date date) {
this.lastUpdated = date;
}
public Date getLastSolved() {
return lastSolved;
}
public void setLastSolved(Date date) {
this.lastSolved = date;
}
public String getOrigin() {
return origin;
}
public void setOrigin(String origin) {
this.origin = origin;
}
public String getRELEASE() {
return release;
}
public void setRELEASE(String release) {
this.release = release;
}
public String getLATEST() {
return latest;
}
public void setLATEST(String latest) {
this.latest = latest;
}
public String getRevision() {
return revision;
}
public boolean isValidSolution() {
return solutionVersion == currentSolutionVersion;
}
public boolean isRefreshRequired() {
return lastUpdated.after(lastDownloaded);
}
private String kvp(Object key, String value) {
if (StringUtils.isEmpty(value)) {
return "";
}
return MessageFormat.format("{0}: {1}\n", key, value);
}
private String kvp(Object key, int value) {
return MessageFormat.format("{0}: {1,number,0}\n", key, value);
}
private String kvp(Object key, Date value) {
if (value == null || value.getTime() == 0) {
return "";
}
DateFormat df = getDateFormat();
return MessageFormat.format("{0}: {1}\n", key, df.format(value));
}
public String toMaxML() {
StringBuilder sb = new StringBuilder();
DateFormat df = getDateFormat();
sb.append(MessageFormat.format("# Moxie data generated {0}\n", df.format(new Date())));
if (!StringUtils.isEmpty(artifactId)) {
sb.append("\n# artifact metadata\n");
sb.append(kvp(Key.groupId, groupId));
sb.append(kvp(Key.artifactId, artifactId));
sb.append(kvp(Key.version, version));
sb.append(kvp(Key.revision, revision));
sb.append(kvp(Key.release, release));
sb.append(kvp(Key.latest, latest));
}
sb.append("\n# Moxie metadata\n");
sb.append(kvp(Key.solutionVersion, currentSolutionVersion));
sb.append(kvp(Key.origin, StringUtils.quote(origin)));
sb.append(kvp(Key.lastDownloaded, lastDownloaded));
sb.append(kvp(Key.lastChecked, lastChecked));
sb.append(kvp(Key.lastUpdated, lastUpdated));
sb.append(kvp(Key.lastSolved, lastSolved));
if (dependencies.size() > 0) {
sb.append("\n# transitive solution\n");
sb.append(MessageFormat.format("{0}:\n", Key.dependencies.name()));
for (Map.Entry<Scope, Set<Dependency>> entry : dependencies.entrySet()) {
for (Dependency dep : entry.getValue()) {
// - solutionScope ring coordinates dependencyScope
sb.append(MessageFormat.format("- {0} {1,number,0} ''{2}'' {3}\n", entry.getKey(), dep.ring, dep.getDetailedCoordinates(), dep.definedScope));
}
}
}
return sb.toString();
}
private DateFormat getDateFormat() {
SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss");
df.setTimeZone(TimeZone.getTimeZone("UTC"));
return df;
}
}