1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17 package org.apache.commons.geometry.examples.io.threed;
18
19 import java.io.File;
20 import java.io.InputStream;
21 import java.io.OutputStream;
22 import java.util.ArrayList;
23 import java.util.Collections;
24 import java.util.List;
25
26 import org.apache.commons.geometry.core.precision.DoublePrecisionContext;
27 import org.apache.commons.geometry.euclidean.threed.BoundarySource3D;
28
29 /** Object that holds an internal registry {@link ModelIOHandler} and delegates
30 * read/write operations to them as determined by their supported model types.
31 *
32 * <p>Instances of this class are thread-safe as long as all registered handlers are
33 * also thread-safe.</p>
34 */
35 public class ModelIOHandlerRegistry implements ModelIOHandler {
36
37 /** Handler list. */
38 private final List<ModelIOHandler> handlers = new ArrayList<>();
39
40 /** Get the {@link ModelIOHandler} for the given type or null if no
41 * handler is found.
42 * @param type model type to retrieve the handler for
43 * @return the handler for the given type or null if no handler is found
44 */
45 public ModelIOHandler getHandlerForType(final String type) {
46 synchronized (handlers) {
47 for (final ModelIOHandler handler : handlers) {
48 if (handler.handlesType(type)) {
49 return handler;
50 }
51 }
52
53 return null;
54 }
55 }
56
57 /** Get the list of registered {@link ModelIOHandler}s.
58 * @return the registered {@link ModelIOHandler}s
59 */
60 public List<ModelIOHandler> getHandlers() {
61 synchronized (handlers) {
62 return Collections.unmodifiableList(new ArrayList<>(handlers));
63 }
64 }
65
66 /** Set the list of registered {@link ModelIOHandler}s.
67 * @param newHandlers the new list of {@link ModelIOHandler}s.
68 */
69 public void setHandlers(final List<ModelIOHandler> newHandlers) {
70 synchronized (handlers) {
71 handlers.clear();
72
73 if (newHandlers != null) {
74 handlers.addAll(newHandlers);
75 }
76 }
77 }
78
79 /** {@inheritDoc} */
80 @Override
81 public boolean handlesType(final String type) {
82 return getHandlerForType(type) != null;
83 }
84
85 /** Read a 3D model from the given file, using the file extension as the model type.
86 * @param in file to read from
87 * @param precision precision context to use in model construction
88 * @return a 3D model represented as a boundary source
89 * @throws java.io.UncheckedIOException if an IO operation fails
90 * @throws IllegalArgumentException if the file does not have a file extension or the
91 * file extension does not indicate a supported model type
92 */
93 public BoundarySource3D read(final File in, final DoublePrecisionContext precision) {
94 return read(getFileExtension(in), in, precision);
95 }
96
97 /** {@inheritDoc} */
98 @Override
99 public BoundarySource3D read(final String type, final File in, final DoublePrecisionContext precision) {
100 return requireHandlerForType(type).read(type, in, precision);
101 }
102
103 /** {@inheritDoc} */
104 @Override
105 public BoundarySource3D read(final String type, final InputStream in, final DoublePrecisionContext precision) {
106 return requireHandlerForType(type).read(type, in, precision);
107 }
108
109 /** Write the model to the file. The file type is determined by the file extension
110 * of the target file.
111 * @param model model to write
112 * @param out output file
113 * @throws java.io.UncheckedIOException if an IO operation fails
114 * @throws IllegalArgumentException if the file does not have a file extension or the
115 * file extension does not indicate a supported model type
116 */
117 public void write(final BoundarySource3D model, final File out) {
118 write(model, getFileExtension(out), out);
119 }
120
121 /** {@inheritDoc} */
122 @Override
123 public void write(final BoundarySource3D model, final String type, final File out) {
124 requireHandlerForType(type).write(model, type, out);
125 }
126
127 /** {@inheritDoc} */
128 @Override
129 public void write(final BoundarySource3D model, final String type, final OutputStream out) {
130 requireHandlerForType(type).write(model, type, out);
131 }
132
133 /** Get the file extension of the given file, throwing an exception if one cannot be found.
134 * @param file the file to get the extension for
135 * @return the file extension
136 * @throws IllegalArgumentException if the file does not have a file extension
137 */
138 private String getFileExtension(final File file) {
139 final String name = file.getName();
140 final int idx = name.lastIndexOf('.');
141 if (idx > -1) {
142 return name.substring(idx + 1).toLowerCase();
143 }
144
145 throw new IllegalArgumentException("Cannot determine target file type: \"" + file +
146 "\" does not have a file extension");
147 }
148
149 /** Get the handler for the given type, throwing an exception if not found.
150 * @param type model type
151 * @return the handler for the given type
152 * @throws IllegalArgumentException if no handler for the type is found
153 */
154 private ModelIOHandler requireHandlerForType(final String type) {
155 final ModelIOHandler handler = getHandlerForType(type);
156 if (handler == null) {
157 throw new IllegalArgumentException("No handler found for type \"" + type + "\"");
158 }
159
160 return handler;
161 }
162 }