Skip to content

Commit 9fe1c22

Browse files
committed
separate model mapper from Yaml
1 parent f6d2e1d commit 9fe1c22

File tree

2 files changed

+157
-112
lines changed

2 files changed

+157
-112
lines changed
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
/*
2+
Copyright 2020 The Kubernetes Authors.
3+
Licensed under the Apache License, Version 2.0 (the "License");
4+
you may not use this file except in compliance with the License.
5+
You may obtain a copy of the License at
6+
http://www.apache.org/licenses/LICENSE-2.0
7+
Unless required by applicable law or agreed to in writing, software
8+
distributed under the License is distributed on an "AS IS" BASIS,
9+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10+
See the License for the specific language governing permissions and
11+
limitations under the License.
12+
*/
13+
package io.kubernetes.client.util;
14+
15+
import com.google.common.collect.ImmutableMap;
16+
import com.google.common.reflect.ClassPath;
17+
import java.io.IOException;
18+
import java.util.ArrayList;
19+
import java.util.HashMap;
20+
import java.util.List;
21+
import java.util.Map;
22+
import java.util.Set;
23+
import org.apache.commons.lang3.tuple.MutablePair;
24+
import org.apache.commons.lang3.tuple.Pair;
25+
import org.slf4j.Logger;
26+
import org.slf4j.LoggerFactory;
27+
28+
/**
29+
* Model mapper loads pre-built kubernetes models from classpath and manages their mapping between
30+
* their apiVersion and kind.
31+
*/
32+
public class ModelMapper {
33+
34+
private static Map<String, Class<?>> classes = new HashMap<>();
35+
private static Map<String, String> apiGroups = new HashMap<>();
36+
private static List<String> apiVersions = new ArrayList<>();
37+
38+
private static final Logger logger = LoggerFactory.getLogger(ModelMapper.class);
39+
40+
static {
41+
try {
42+
initModelMap();
43+
} catch (Exception ex) {
44+
logger.error("Unexpected exception while loading classes: " + ex);
45+
}
46+
}
47+
48+
/**
49+
* Add a mapping from API Group/version/kind to a Class to use when calling <code>load(...)
50+
* </code> .
51+
*
52+
* <p>Shouldn't really be needed as most API Group/Version/Kind are loaded dynamically at startup.
53+
*/
54+
public static void addModelMap(String apiGroupVersion, String kind, Class<?> clazz) {
55+
classes.put(apiGroupVersion + "/" + kind, clazz);
56+
}
57+
58+
public static Class<?> getApiTypeClass(String apiVersion, String kind) {
59+
Class<?> clazz = (Class<?>) classes.get(apiVersion + "/" + kind);
60+
if (clazz == null) {
61+
// Attempt to detect class from version and kind alone
62+
if (apiVersion.contains("/")) {
63+
clazz = (Class<?>) classes.get(apiVersion.split("/")[1] + "/" + kind);
64+
}
65+
}
66+
return clazz;
67+
}
68+
69+
public static Map<String, Class<?>> getAllKnownClasses() {
70+
return ImmutableMap.copyOf(classes);
71+
}
72+
73+
private static void initApiGroupMap() {
74+
apiGroups.put("Admissionregistration", "admissionregistration.k8s.io");
75+
apiGroups.put("Apiextensions", "apiextensions.k8s.io");
76+
apiGroups.put("Apiregistration", "apiregistration.k8s.io");
77+
apiGroups.put("Apps", "apps");
78+
apiGroups.put("Authentication", "authentication.k8s.io");
79+
apiGroups.put("Authorization", "authorization.k8s.io");
80+
apiGroups.put("Autoscaling", "autoscaling");
81+
apiGroups.put("Extensions", "extensions");
82+
apiGroups.put("Batch", "batch");
83+
apiGroups.put("Certificates", "certificates.k8s.io");
84+
apiGroups.put("Networking", "networking.k8s.io");
85+
apiGroups.put("Policy", "policy");
86+
apiGroups.put("RbacAuthorization", "rbac.authorization.k8s.io");
87+
apiGroups.put("Scheduling", "scheduling.k8s.io");
88+
apiGroups.put("Settings", "settings.k8s.io");
89+
apiGroups.put("Storage", "storage.k8s.io");
90+
}
91+
92+
private static void initApiVersionList() {
93+
// Order important
94+
apiVersions.add("V2beta1");
95+
apiVersions.add("V2beta2");
96+
apiVersions.add("V2alpha1");
97+
apiVersions.add("V1beta2");
98+
apiVersions.add("V1beta1");
99+
apiVersions.add("V1alpha1");
100+
apiVersions.add("V1");
101+
}
102+
103+
private static Pair<String, String> getApiVersion(String name) {
104+
MutablePair<String, String> parts = new MutablePair<>();
105+
for (String version : apiVersions) {
106+
if (name.startsWith(version)) {
107+
parts.left = version.toLowerCase();
108+
parts.right = name.substring(version.length());
109+
break;
110+
}
111+
}
112+
if (parts.left == null) parts.right = name;
113+
114+
return parts;
115+
}
116+
117+
private static void initModelMap() throws IOException {
118+
initApiGroupMap();
119+
initApiVersionList();
120+
121+
ClassPath cp = ClassPath.from(Yaml.class.getClassLoader());
122+
Set<ClassPath.ClassInfo> allClasses =
123+
cp.getTopLevelClasses("io.kubernetes.client.openapi.models");
124+
125+
for (ClassPath.ClassInfo clazz : allClasses) {
126+
String modelName = "";
127+
Pair<String, String> nameParts = getApiGroup(clazz.getSimpleName());
128+
modelName += nameParts.getLeft() == null ? "" : nameParts.getLeft() + "/";
129+
130+
nameParts = getApiVersion(nameParts.getRight());
131+
modelName += nameParts.getLeft() == null ? "" : nameParts.getLeft() + "/";
132+
modelName += nameParts.getRight();
133+
134+
classes.put(modelName, clazz.load());
135+
}
136+
}
137+
138+
private static Pair<String, String> getApiGroup(String name) {
139+
MutablePair<String, String> parts = new MutablePair<>();
140+
for (Map.Entry<String, String> entry : apiGroups.entrySet()) {
141+
if (name.startsWith(entry.getKey())) {
142+
parts.left = entry.getValue();
143+
parts.right = name.substring(entry.getKey().length());
144+
break;
145+
}
146+
}
147+
if (parts.left == null) parts.right = name;
148+
return parts;
149+
}
150+
}

util/src/main/java/io/kubernetes/client/util/Yaml.java

Lines changed: 7 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
*/
1313
package io.kubernetes.client.util;
1414

15-
import com.google.common.reflect.ClassPath;
1615
import io.kubernetes.client.custom.IntOrString;
1716
import io.kubernetes.client.custom.Quantity;
1817
import java.io.File;
@@ -24,14 +23,11 @@
2423
import java.util.ArrayList;
2524
import java.util.Collections;
2625
import java.util.Comparator;
27-
import java.util.HashMap;
2826
import java.util.Iterator;
2927
import java.util.List;
3028
import java.util.Map;
3129
import java.util.Set;
3230
import okio.ByteString;
33-
import org.apache.commons.lang3.tuple.MutablePair;
34-
import org.apache.commons.lang3.tuple.Pair;
3531
import org.joda.time.DateTime;
3632
import org.joda.time.DateTimeZone;
3733
import org.slf4j.Logger;
@@ -48,109 +44,9 @@
4844
import org.yaml.snakeyaml.representer.Representer;
4945

5046
public class Yaml {
51-
private static Map<String, Class<?>> classes = new HashMap<>();
52-
private static Map<String, String> apiGroups = new HashMap<>();
53-
private static List<String> apiVersions = new ArrayList<>();
5447

5548
static final Logger logger = LoggerFactory.getLogger(Yaml.class);
5649

57-
private static void initApiGroupMap() {
58-
apiGroups.put("Admissionregistration", "admissionregistration.k8s.io");
59-
apiGroups.put("Apiextensions", "apiextensions.k8s.io");
60-
apiGroups.put("Apiregistration", "apiregistration.k8s.io");
61-
apiGroups.put("Apps", "apps");
62-
apiGroups.put("Authentication", "authentication.k8s.io");
63-
apiGroups.put("Authorization", "authorization.k8s.io");
64-
apiGroups.put("Autoscaling", "autoscaling");
65-
apiGroups.put("Extensions", "extensions");
66-
apiGroups.put("Batch", "batch");
67-
apiGroups.put("Certificates", "certificates.k8s.io");
68-
apiGroups.put("Networking", "networking.k8s.io");
69-
apiGroups.put("Policy", "policy");
70-
apiGroups.put("RbacAuthorization", "rbac.authorization.k8s.io");
71-
apiGroups.put("Scheduling", "scheduling.k8s.io");
72-
apiGroups.put("Settings", "settings.k8s.io");
73-
apiGroups.put("Storage", "storage.k8s.io");
74-
}
75-
76-
private static void initApiVersionList() {
77-
// Order important
78-
apiVersions.add("V2beta1");
79-
apiVersions.add("V2beta2");
80-
apiVersions.add("V2alpha1");
81-
apiVersions.add("V1beta2");
82-
apiVersions.add("V1beta1");
83-
apiVersions.add("V1alpha1");
84-
apiVersions.add("V1");
85-
}
86-
87-
private static Pair<String, String> getApiGroup(String name) {
88-
MutablePair<String, String> parts = new MutablePair<>();
89-
for (Map.Entry<String, String> entry : apiGroups.entrySet()) {
90-
if (name.startsWith(entry.getKey())) {
91-
parts.left = entry.getValue();
92-
parts.right = name.substring(entry.getKey().length());
93-
break;
94-
}
95-
}
96-
if (parts.left == null) parts.right = name;
97-
98-
return parts;
99-
}
100-
101-
private static Pair<String, String> getApiVersion(String name) {
102-
MutablePair<String, String> parts = new MutablePair<>();
103-
for (String version : apiVersions) {
104-
if (name.startsWith(version)) {
105-
parts.left = version.toLowerCase();
106-
parts.right = name.substring(version.length());
107-
break;
108-
}
109-
}
110-
if (parts.left == null) parts.right = name;
111-
112-
return parts;
113-
}
114-
115-
private static void initModelMap() throws IOException {
116-
initApiGroupMap();
117-
initApiVersionList();
118-
119-
ClassPath cp = ClassPath.from(Yaml.class.getClassLoader());
120-
Set<ClassPath.ClassInfo> allClasses =
121-
cp.getTopLevelClasses("io.kubernetes.client.openapi.models");
122-
123-
for (ClassPath.ClassInfo clazz : allClasses) {
124-
String modelName = "";
125-
Pair<String, String> nameParts = getApiGroup(clazz.getSimpleName());
126-
modelName += nameParts.getLeft() == null ? "" : nameParts.getLeft() + "/";
127-
128-
nameParts = getApiVersion(nameParts.getRight());
129-
modelName += nameParts.getLeft() == null ? "" : nameParts.getLeft() + "/";
130-
modelName += nameParts.getRight();
131-
132-
classes.put(modelName, clazz.load());
133-
}
134-
}
135-
136-
static {
137-
try {
138-
initModelMap();
139-
} catch (Exception ex) {
140-
logger.error("Unexpected exception while loading classes: " + ex);
141-
}
142-
}
143-
144-
/**
145-
* Add a mapping from API Group/version/kind to a Class to use when calling <code>load(...)
146-
* </code> .
147-
*
148-
* <p>Shouldn't really be needed as most API Group/Version/Kind are loaded dynamically at startup.
149-
*/
150-
public static void addModelMap(String apiGroupVersion, String kind, Class<?> clazz) {
151-
classes.put(apiGroupVersion + "/" + kind, clazz);
152-
}
153-
15450
/**
15551
* Load an API object from a YAML string representation. Returns a concrete typed object (e.g.
15652
* V1Pod)
@@ -480,22 +376,21 @@ private static Object modelMapper(Map<String, Object> data) throws IOException {
480376
throw new IOException("Missing apiVersion in YAML file!");
481377
}
482378

483-
Class<?> clazz = (Class<?>) classes.get(apiVersion + "/" + kind);
484-
if (clazz == null) {
485-
// Attempt to detect class from version and kind alone
486-
if (apiVersion.contains("/")) {
487-
clazz = (Class<?>) classes.get(apiVersion.split("/")[1] + "/" + kind);
488-
}
489-
}
379+
Class<?> clazz = ModelMapper.getApiTypeClass(apiVersion, kind);
490380
if (clazz == null) {
491381
throw new IOException(
492382
"Unknown apiVersionKind: "
493383
+ apiVersion
494384
+ "/"
495385
+ kind
496386
+ " known kinds are: "
497-
+ classes.toString());
387+
+ ModelMapper.getAllKnownClasses());
498388
}
499389
return loadAs(new StringReader(getSnakeYaml().dump(data)), clazz);
500390
}
391+
392+
@Deprecated
393+
public static void addModelMap(String apiGroupVersion, String kind, Class<?> clazz) {
394+
ModelMapper.addModelMap(apiGroupVersion, kind, clazz);
395+
}
501396
}

0 commit comments

Comments
 (0)