1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package io.wcm.devops.conga.plugins.aem.maven.model;
21
22 import static io.wcm.devops.conga.generator.util.FileUtil.getCanonicalPath;
23 import static io.wcm.devops.conga.plugins.aem.maven.model.ParserUtil.children;
24 import static io.wcm.devops.conga.plugins.aem.maven.model.ParserUtil.getVariants;
25 import static io.wcm.devops.conga.plugins.aem.maven.model.ParserUtil.toStringSet;
26
27 import java.io.File;
28 import java.io.FileInputStream;
29 import java.io.IOException;
30 import java.io.InputStream;
31 import java.io.InputStreamReader;
32 import java.io.Reader;
33 import java.nio.charset.StandardCharsets;
34 import java.util.ArrayList;
35 import java.util.LinkedHashSet;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Objects;
39 import java.util.Set;
40 import java.util.jar.JarFile;
41 import java.util.jar.Manifest;
42
43 import org.apache.commons.io.FilenameUtils;
44 import org.apache.commons.lang3.StringUtils;
45 import org.osgi.framework.Constants;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48 import org.yaml.snakeyaml.Yaml;
49
50 import io.wcm.devops.conga.model.util.MapExpander;
51 import io.wcm.devops.conga.plugins.aem.postprocessor.ContentPackagePropertiesPostProcessor;
52
53
54
55
56 public final class ModelParser {
57
58
59
60
61 public static final String MODEL_FILE = "model.yaml";
62
63 private static final String PROP_ROLES = "roles";
64 private static final String PROP_ROLE = "role";
65 private static final String PROP_CONFIG = "config";
66 private static final String PROP_FILES = "files";
67
68 private static final Logger log = LoggerFactory.getLogger(ModelParser.class);
69
70 private final Yaml yaml;
71 private final File nodeDir;
72 private final Map<String, Object> modelData;
73
74
75
76
77 public ModelParser(File nodeDir) {
78 this.yaml = YamlUtil.createYaml();
79 this.nodeDir = nodeDir;
80 this.modelData = getModelData();
81 }
82
83
84
85
86
87 public List<InstallableFile> getInstallableFilesForNode() {
88 List<InstallableFile> items = new ArrayList<>();
89 for (Map<String, Object> role : children(modelData, PROP_ROLES)) {
90 List<String> variants = getVariants(role);
91 for (Map<String, Object> fileData : children(role, PROP_FILES)) {
92 String path = Objects.toString(fileData.get("path"), null);
93 File file = new File(nodeDir, path);
94 if (isContentPackage(fileData)) {
95 items.add(new ModelContentPackageFile(file, fileData, variants));
96 }
97 else if (isOsgiBundle(file)) {
98 items.add(new BundleFile(file, fileData, variants));
99 }
100 }
101 }
102 return items;
103 }
104
105
106
107
108
109
110 public boolean hasRole(String roleName) {
111 for (Map<String, Object> role : children(modelData, PROP_ROLES)) {
112 if (StringUtils.equals(Objects.toString(role.get(PROP_ROLE), null), roleName)) {
113 return true;
114 }
115 }
116 return false;
117 }
118
119
120
121
122
123 @SuppressWarnings("unchecked")
124 public Set<String> getCloudManagerTarget() {
125 Set<String> targets = new LinkedHashSet<>();
126 for (Map<String, Object> role : children(modelData, PROP_ROLES)) {
127 Map<String, Object> config = (Map<String, Object>)role.get(PROP_CONFIG);
128 if (config != null) {
129 Object targetValue = MapExpander.getDeep(config, "cloudManager.target");
130 if (targetValue != null) {
131 targets.addAll(toStringSet(targetValue));
132 }
133 }
134 }
135 return targets;
136 }
137
138 @SuppressWarnings("java:S112")
139 private Map<String, Object> getModelData() {
140 File modelFile = new File(nodeDir, MODEL_FILE);
141 if (!modelFile.exists() || !modelFile.isFile()) {
142 throw new RuntimeException("Model file not found: " + getCanonicalPath(modelFile));
143 }
144 return parseYaml(modelFile);
145 }
146
147 @SuppressWarnings("java:S112")
148 private Map<String, Object> parseYaml(File modelFile) {
149 try {
150 try (InputStream is = new FileInputStream(modelFile);
151 Reader reader = new InputStreamReader(is, StandardCharsets.UTF_8)) {
152 return yaml.loadAs(reader, Map.class);
153 }
154 }
155 catch (IOException ex) {
156 throw new RuntimeException("Unable to parse " + getCanonicalPath(modelFile), ex);
157 }
158 }
159
160 private boolean isContentPackage(Map<String, Object> fileData) {
161 return fileData.get(ContentPackagePropertiesPostProcessor.MODEL_OPTIONS_PROPERTY) != null;
162 }
163
164 private boolean isOsgiBundle(File file) {
165 if (!StringUtils.equals(FilenameUtils.getExtension((file.getName())), "jar")) {
166 return false;
167 }
168 try (JarFile jarFile = new JarFile(file)) {
169 Manifest manifest = jarFile.getManifest();
170 if (manifest != null) {
171 return manifest.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME) != null;
172 }
173 }
174 catch (IOException ex) {
175 log.debug("Unable to check for OSGi bundle: {}", file, ex);
176 }
177 return false;
178 }
179
180 }