View Javadoc
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 }