1 /*
2  * This file is part of libbluray
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library. If not, see
16  * <http://www.gnu.org/licenses/>.
17  */
18 
19 package javax.media;
20 
21 import java.io.IOException;
22 import java.net.URL;
23 import java.util.Vector;
24 
25 import javax.media.protocol.DataSource;
26 import javax.media.protocol.URLDataSource;
27 
28 import org.videolan.Logger;
29 
30 /**
31  * This file is a stripped down version of the Manager class from FMJ (fmj-sf.net)
32  * @author Ken Larson
33  *
34  */
35 public final class Manager {
createPlayer(URL sourceURL)36     public static Player createPlayer(URL sourceURL) throws IOException,
37             NoPlayerException {
38         return createPlayer(new MediaLocator(sourceURL));
39     }
40 
createPlayer(MediaLocator sourceLocator)41     public static Player createPlayer(MediaLocator sourceLocator)
42             throws IOException, NoPlayerException {
43         final String protocol = sourceLocator.getProtocol();
44         final Vector dataSourceList = getDataSourceList(protocol);
45         for (int i = 0; i < dataSourceList.size(); ++i) {
46             String dataSourceClassName = (String) dataSourceList.get(i);
47             try {
48                 final Class dataSourceClass = Class.forName(dataSourceClassName);
49                 final DataSource dataSource = (DataSource) dataSourceClass.newInstance();
50                 dataSource.setLocator(sourceLocator);
51                 dataSource.connect();
52                 return createPlayer(dataSource);
53 
54                 // TODO: JMF seems to disconnect data sources in this method, based on this stack trace:
55 //              java.lang.NullPointerException
56 //              at com.sun.media.protocol.rtp.DataSource.disconnect(DataSource.java:207)
57 //              at javax.media.Manager.createPlayer(Manager.java:425)
58 //              at net.sf.fmj.ui.application.ContainerPlayer.createNewPlayer(ContainerPlayer.java:357)
59             } catch (NoPlayerException e) {
60                 // no need to log, will be logged by call to createPlayer.
61                 continue;
62             } catch (ClassNotFoundException e) {
63                 logger.warning("createPlayer: " + e);    // no need for call stack
64                 continue;
65             } catch (IOException e) {
66                 logger.warning(""  + e);
67                 continue;
68             } catch (NoClassDefFoundError e) {
69                 logger.warning(""  + e);
70                 continue;
71             } catch (Exception e) {
72                 logger.warning(""  + e);
73                 continue;
74             }
75         }
76 
77         // if none found, try URLDataSource:
78         final URL url;
79         try {
80             url = sourceLocator.getURL();
81         } catch (Exception e) {
82             logger.warning("" + e);
83             throw new NoPlayerException();
84         }
85         final URLDataSource dataSource = new URLDataSource(url);
86         dataSource.connect();   // TODO: there is a problem because we connect to the datasource here, but
87                                 // the following call may try twice or more to use the datasource with a player, once
88                                 // for the right content type, and multiple times for unknown.  The first attempt (for example) may actually
89                                 // read data, in which case the second one will be missing data when it reads.
90                                 // really, the datasource needs to be recreated.
91                                 // The workaround for now is that URLDataSource (and others) allows repeated connect() calls.
92         return createPlayer(dataSource);
93     }
94 
createPlayer(DataSource source)95     public static Player createPlayer(DataSource source) throws IOException, NoPlayerException {
96         return createPlayer(source, source.getContentType());
97     }
98 
createDataSource(URL sourceURL)99     public static DataSource createDataSource(URL sourceURL)
100             throws IOException, NoDataSourceException {
101         return createDataSource(new MediaLocator(sourceURL));
102     }
103 
createDataSource(MediaLocator sourceLocator)104     public static DataSource createDataSource(MediaLocator sourceLocator)
105             throws IOException, NoDataSourceException {
106         final String protocol = sourceLocator.getProtocol();
107         final Vector dataSourceList = getDataSourceList(protocol);
108         for (int i = 0; i < dataSourceList.size(); ++i) {
109             String dataSourceClassName = (String) dataSourceList.get(i);
110             try {
111                 final Class dataSourceClass = Class.forName(dataSourceClassName);
112                 final DataSource dataSource = (DataSource) dataSourceClass.newInstance();
113                 dataSource.setLocator(sourceLocator);
114                 dataSource.connect();
115                 return dataSource;
116             } catch (ClassNotFoundException e) {
117                 logger.warning("createDataSource: "  + e);    // no need for call stack
118                 continue;
119             } catch (IOException e) {
120                 logger.warning("" + e);
121                 continue;
122             } catch (NoClassDefFoundError e) {
123                 logger.warning("" + e);
124                 continue;
125             } catch (Exception e) {
126                 logger.warning("" + e);
127                 continue;
128             }
129         }
130 
131         // if none found, try URLDataSource:
132         final URL url;
133         try {
134             url = sourceLocator.getURL();
135         } catch (Exception e) {
136             logger.warning("" + e);
137             throw new NoDataSourceException();
138         }
139         final URLDataSource dataSource = new URLDataSource(url);
140         dataSource.connect();
141         return dataSource;
142     }
143 
getSystemTimeBase()144     public static TimeBase getSystemTimeBase() {
145         return systemTimeBase;
146     }
147 
getDataSourceList(String protocolName)148     public static Vector getDataSourceList(String protocolName) {
149         return getClassList(protocolName, PackageManager.getProtocolPrefixList(), "protocol", "DataSource");
150     }
151 
getHandlerClassList(String contentName)152     public static Vector getHandlerClassList(String contentName) {
153         return getClassList(toPackageFriendly(contentName), PackageManager.getContentPrefixList(), "content", "Handler");
154     }
155 
createPlayer(DataSource source, String contentType)156     private static Player createPlayer(DataSource source, String contentType)
157         throws IOException, NoPlayerException {
158         final Vector handlerClassList = getHandlerClassList(contentType);
159         for (int i = 0; i < handlerClassList.size(); ++i) {
160             final String handlerClassName = (String) handlerClassList.get(i);
161 
162             try {
163                 System.out.println(handlerClassName);
164                 final Class handlerClass = Class.forName(handlerClassName);
165                 if (!Player.class.isAssignableFrom(handlerClass) &&
166                     !MediaProxy.class.isAssignableFrom(handlerClass)) {
167                     continue;   // skip any classes that will not be matched below.
168                 }
169                 final MediaHandler handler = (MediaHandler) handlerClass.newInstance();
170                 handler.setSource(source);
171 
172                 if (handler instanceof Player) {
173                     return (Player) handler;
174                 } else if (handler instanceof MediaProxy) {
175                     final MediaProxy mediaProxy = (MediaProxy) handler;
176                     return createPlayer(mediaProxy.getDataSource());
177                 }
178             } catch (ClassNotFoundException e) {
179                 // no need for call stack
180                 logger.warning("createPlayer: "  + e);
181                 continue;
182             } catch (IncompatibleSourceException e) {
183                 // no need for call stack
184                 logger.warning("createPlayer(" + source + ", " + contentType + "): "  + e);
185                 continue;
186             } catch (IOException e) {
187                 logger.warning("" + e);
188                 continue;
189             } catch (NoPlayerException e) {
190                 // no need to log, will be logged by call to createPlayer.
191                 continue;
192             } catch (NoClassDefFoundError e) {
193                 logger.warning("" + e);
194                 continue;
195             } catch (Exception e) {
196                 logger.warning("" + e);
197                 continue;
198             }
199         }
200         logger.error("No player found for " + contentType + " / " + source.getLocator());
201         throw new NoPlayerException("No player found for " + source.getLocator());
202     }
203 
toPackageFriendly(char c)204     private static char toPackageFriendly(char c) {
205         if (c >= 'a' && c <= 'z')
206             return c;
207         else if (c >= 'A' && c <= 'Z')
208             return c;
209         else if (c >= '0' && c <= '9')
210             return c;
211         else if (c == '.')
212             return c;
213         else if (c == '/')
214             return '.';
215         else
216             return '_';
217     }
218 
toPackageFriendly(String contentName)219     private static String toPackageFriendly(String contentName) {
220         final StringBuffer b = new StringBuffer();
221         for (int i = 0; i < contentName.length(); ++i) {
222             final char c = contentName.charAt(i);
223             b.append(toPackageFriendly(c));
224         }
225         return b.toString();
226     }
227 
getClassList(String contentName, Vector packages, String component2, String className)228     public static Vector getClassList(String contentName, Vector packages, String component2, String className) {
229         final Vector result = new Vector();
230         //result.add("media." + component2 + "." + contentName + "." + className);
231 
232         for (int i = 0; i < packages.size(); ++i) {
233             result.add(((String) packages.get(i)) + ".media." + component2 + "." + contentName + "." + className);
234         }
235 
236         return result;
237     }
238 
239     public static final String UNKNOWN_CONTENT_NAME = "unknown";
240 
241     private static final TimeBase systemTimeBase = new SystemTimeBase();
242     private static final Logger logger = Logger.getLogger(Manager.class.getName());
243 }
244