--- /dev/null
+<?xml version='1.0' encoding='UTF-8'?>
+
+<!--
+ ~ Copyright (c) 2015. Developed by Hedgecode.
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+
+ <!--parent>
+ <groupId>org.hedgecode.maven</groupId>
+ <artifactId>maven-parent</artifactId>
+ <version>1</version>
+ </parent-->
+
+ <groupId>org.hedgecode.xml</groupId>
+ <artifactId>hespiff</artifactId>
+ <version>0.1-SNAPSHOT</version>
+ <packaging>jar</packaging>
+
+ <name>Hedgecode XSPF API</name>
+ <description>
+ Hedgecode XSPF API.
+ </description>
+ <inceptionYear>2015</inceptionYear>
+
+ <url>http://hedgecode.org/xml/${project.artifactId}/</url>
+
+ <scm>
+ <connection>scm:svn:http://svn.hedgecode.org/xml/${project.artifactId}/trunk/</connection>
+ <developerConnection>scm:svn:http://svn.hedgecode.org/xml/${project.artifactId}/trunk/</developerConnection>
+ <url>http://svn.hedgecode.org/xml/${project.artifactId}/trunk/</url>
+ </scm>
+
+ <properties>
+ <javaVersion>7</javaVersion>
+ <maven.compiler.source>1.${javaVersion}</maven.compiler.source>
+ <maven.compiler.target>1.${javaVersion}</maven.compiler.target>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+ <junitVersion>4.8.2</junitVersion>
+
+ <project.package>${project.groupId}.xspf</project.package>
+ <xsd.directory>${project.basedir}/src/main/xsd</xsd.directory>
+ <xsd.filename>xspf-1_0.2</xsd.filename>
+ <relaxng.directory>${project.basedir}/src/main/rng</relaxng.directory>
+ <relaxng.filename>xspf-1_0.7</relaxng.filename>
+ <generated.xsd.directory>${project.build.directory}/generated-xsd</generated.xsd.directory>
+ <generated.sources.directory>${project.build.directory}/generated-sources</generated.sources.directory>
+ <generated.meta.directory>${project.build.outputDirectory}/META-INF</generated.meta.directory>
+
+ <!--mavenDependencyPluginVersion>2.8</mavenDependencyPluginVersion>
+ <mavenJarPluginVersion>2.5</mavenJarPluginVersion>
+ <mavenAssemblyPluginVersion>2.4.1</mavenAssemblyPluginVersion>
+ <mavenReleasePluginVersion>2.5.3</mavenReleasePluginVersion-->
+
+ <issueKeyNumber>LIB-4</issueKeyNumber>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <version>${junitVersion}</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <!--plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <version>2.7</version>
+ <executions>
+ <execution>
+ <id>copy-xsd</id>
+ <phase>validate</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${generated.xsd.directory}</outputDirectory>
+ <resources>
+ <resource>
+ <directory>${xsd.directory}</directory>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin-->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-resources-plugin</artifactId>
+ <version>2.7</version>
+ <executions>
+ <execution>
+ <id>copy-xsd</id>
+ <phase>validate</phase>
+ <goals>
+ <goal>copy-resources</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${generated.meta.directory}</outputDirectory>
+ <resources>
+ <resource>
+ <directory>${xsd.directory}</directory>
+ </resource>
+ <resource>
+ <directory>${relaxng.directory}</directory>
+ </resource>
+ </resources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>us.bryon</groupId>
+ <artifactId>relaxng-maven-plugin</artifactId>
+ <version>1.1</version>
+ <executions>
+ <execution>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>trang</goal>
+ </goals>
+ <configuration>
+ <translations>
+ <translation>
+ <in>${relaxng.directory}/${relaxng.filename}.rng</in>
+ <out>${generated.xsd.directory}/${relaxng.filename}.xsd</out>
+ </translation>
+ </translations>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>jaxb2-maven-plugin</artifactId>
+ <version>2.2</version>
+ <executions>
+ <execution>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>xjc</goal>
+ </goals>
+ <configuration>
+ <outputDirectory>${generated.sources.directory}/xsd</outputDirectory>
+ <packageName>${project.package}.xsd</packageName>
+ <arguments>
+ <argument>-episode</argument>
+ <argument>${generated.meta.directory}/xsd-jaxb.episode</argument>
+ </arguments>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.jvnet.jaxb2.maven2</groupId>
+ <artifactId>maven-jaxb2-plugin</artifactId>
+ <version>0.13.1</version>
+ <executions>
+ <execution>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>generate</goal>
+ </goals>
+ <configuration>
+ <schemaDirectory>${generated.xsd.directory}</schemaDirectory>
+ <generateDirectory>${generated.sources.directory}/rng</generateDirectory>
+ <generatePackage>${project.package}.rng</generatePackage>
+ <episodeFile>${generated.meta.directory}/rng-jaxb.episode</episodeFile>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>build-helper-maven-plugin</artifactId>
+ <version>1.9.1</version>
+ <executions>
+ <execution>
+ <phase>generate-sources</phase>
+ <goals>
+ <goal>add-source</goal>
+ </goals>
+ <configuration>
+ <sources>
+ <source>${generated.sources.directory}/xsd</source>
+ <source>${generated.sources.directory}/rng</source>
+ </sources>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf;
+
+import java.util.List;
+
+import org.hedgecode.xml.xspf.bind.Binder;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public abstract class AbstractXMLBindElement implements Element {
+
+ protected abstract Binder getBinder();
+
+ @Override
+ public String getTitle() {
+ return getBinder().getTitle();
+ }
+
+ @Override
+ public void setTitle(String title) {
+ getBinder().setTitle(title);
+ }
+
+ @Override
+ public String getCreator() {
+ return getBinder().getCreator();
+ }
+
+ @Override
+ public void setCreator(String creator) {
+ getBinder().setCreator(creator);
+ }
+
+ @Override
+ public String getAnnotation() {
+ return getBinder().getAnnotation();
+ }
+
+ @Override
+ public void setAnnotation(String annotation) {
+ getBinder().setAnnotation(annotation);
+ }
+
+ @Override
+ public String getInfo() {
+ return getBinder().getInfo();
+ }
+
+ @Override
+ public void setInfo(String info) {
+ getBinder().setInfo(info);
+ }
+
+ @Override
+ public String getImage() {
+ return getBinder().getImage();
+ }
+
+ @Override
+ public void setImage(String image) {
+ getBinder().setImage(image);
+ }
+
+ @Override
+ public List<Link> getLinks() {
+ return getBinder().getLinks();
+ }
+
+ @Override
+ public void addLink(Link link) {
+ getBinder().addLink(link);
+ }
+
+ @Override
+ public List<Meta> getMetas() {
+ return getBinder().getMetas();
+ }
+
+ @Override
+ public void addMeta(Meta meta) {
+ getBinder().addMeta(meta);
+ }
+
+ @Override
+ public List<Extension> getExtensions() {
+ return getBinder().getExtensions();
+ }
+
+ @Override
+ public void addExtension(Extension extension) {
+ getBinder().addExtension(extension);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf;
+
+import java.util.Map;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface Attribution {
+
+ Map<String, String> get();
+
+ void add(String identifier, String location);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf;
+
+import java.util.List;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface Element {
+
+ String getTitle();
+
+ void setTitle(String title);
+
+ String getCreator();
+
+ void setCreator(String creator);
+
+ String getAnnotation();
+
+ void setAnnotation(String annotation);
+
+ String getInfo();
+
+ void setInfo(String info);
+
+ String getImage();
+
+ void setImage(String image);
+
+ List<Link> getLinks();
+
+ void addLink(Link link);
+
+ List<Meta> getMetas();
+
+ void addMeta(Meta meta);
+
+ List<Extension> getExtensions();
+
+ void addExtension(Extension extension);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf;
+
+import java.util.List;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface Extension {
+
+ String getApplication();
+
+ List<Object> getContent();
+
+ void set(String application, List<Object> content);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface Link {
+
+ String getRel();
+
+ String getContent();
+
+ void set(String rel, String content);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface Meta {
+
+ String getRel();
+
+ String getContent();
+
+ void set(String rel, String content);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf;
+
+import java.io.File;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.util.Date;
+import java.util.List;
+
+import javax.xml.bind.JAXBException;
+
+import org.hedgecode.xml.xspf.validate.ValidateException;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface Playlist extends Element {
+
+ String getLocation();
+
+ void setLocation(String location);
+
+ String getIdentifier();
+
+ void setIdentifier(String identifier);
+
+ Date getDate();
+
+ void setDate(Date date);
+
+ String getLicense();
+
+ void setLicense(String license);
+
+ Attribution getAttribution();
+
+ void setAttribution(Attribution attribution);
+
+ List<Track> getTracks();
+
+ void addTrack(Track track);
+
+ void read(File inputFile) throws JAXBException;
+
+ void write(File outputFile) throws JAXBException;
+
+ public OutputStream getAsStream() throws JAXBException;
+
+ public String getAsString() throws JAXBException, UnsupportedEncodingException;
+
+ void validate() throws ValidateException;
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf;
+
+import java.util.List;
+
+import org.hedgecode.xml.xspf.bind.TrackBinder;
+
+import static org.hedgecode.xml.xspf.XSPFConstants.Format;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class PlaylistFactory {
+
+ public static Playlist createPlaylist(Format format) {
+ return new XSPFPlaylist(format);
+ }
+
+ public static Track createTrack() {
+ return new XSPFTrack();
+ }
+
+ public static Track createTrack(TrackBinder trackBinder) {
+ XSPFTrack track = new XSPFTrack();
+ track.unbind(
+ new XMLBindTrack(trackBinder)
+ );
+ return track;
+ }
+
+ public static void bindTrack(Track track, TrackBinder trackBinder) {
+ if (track instanceof XSPFTrack)
+ ((XSPFTrack)track).bind(
+ new XMLBindTrack(trackBinder)
+ );
+ }
+
+ public static Attribution createAttribution() {
+ Attribution attribution = new XSPFAttribution();
+ return attribution;
+ }
+
+ public static Attribution createAttribution(String identifier, String location) {
+ Attribution attribution = new XSPFAttribution();
+ attribution.add(identifier, location);
+ return attribution;
+ }
+
+ public static Link createLink(String rel, String content) {
+ return new XSPFLink(rel, content);
+ }
+
+ public static Meta createMeta(String rel, String content) {
+ return new XSPFMeta(rel, content);
+ }
+
+ public static Extension createExtension(String application, List<Object> content) {
+ return new XSPFExtension(application, content);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class Properties {
+
+ public static final String CHARSET = "xspf.charset";
+ public static final String FORMATTED = "xspf.formatted";
+ public static final String STANDALONE = "xspf.standalone";
+
+ private static final Map<String, Object> props = new HashMap<String, Object>() {
+ {
+ put(CHARSET, XSPFConstants.DEF_CHARSET);
+ put(FORMATTED, Boolean.TRUE);
+ put(STANDALONE, Boolean.FALSE);
+ }
+ };
+
+ public static void setProperty(String name, Object value) {
+ if (props.containsKey(name)) {
+ if (props.get(name).getClass().equals(value.getClass()))
+ props.put(name, value);
+ }
+ }
+
+ public static Object getProperty(String name, Class<?> clazz) {
+ if (clazz != null && props.containsKey(name)) {
+ Object property = props.get(name);
+ if (clazz.isAssignableFrom(property.getClass()))
+ return property;
+ }
+ return null;
+ }
+
+ private Properties() {
+ throw new AssertionError(
+ "I am so paranoid!"
+ );
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf;
+
+import java.util.List;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface Track extends Element {
+
+ List<String> getLocations();
+
+ void addLocation(String location);
+
+ List<String> getIdentifiers();
+
+ void addIdentifier(String identifier);
+
+ String getAlbum();
+
+ void setAlbum(String album);
+
+ Integer getTrackNum();
+
+ void setTrackNum(Integer trackNum);
+
+ Integer getDuration();
+
+ void setDuration(Integer duration);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
+import java.util.Date;
+import java.util.List;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.JAXBException;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.Unmarshaller;
+import javax.xml.bind.annotation.XmlRootElement;
+
+import org.hedgecode.xml.xspf.bind.Binder;
+import org.hedgecode.xml.xspf.bind.BinderFactory;
+import org.hedgecode.xml.xspf.bind.PlaylistBinder;
+import org.hedgecode.xml.xspf.validate.ValidateException;
+
+import static org.hedgecode.xml.xspf.XSPFConstants.Format;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class XMLBindPlaylist extends AbstractXMLBindElement implements Playlist {
+
+ private PlaylistBinder binder;
+
+ protected XMLBindPlaylist(PlaylistBinder binder) {
+ if (binder == null)
+ this.binder = BinderFactory.createPlaylistBinder();
+ else
+ this.binder = binder;
+ setDefaults();
+ }
+
+ protected XMLBindPlaylist(Format format) {
+ this.binder = BinderFactory.createPlaylistBinder(format);
+ setDefaults();
+ }
+
+ private void setDefaults() {
+ binder.setVersion(XSPFConstants.XSPF_VERSION);
+ }
+
+ @Override
+ protected Binder getBinder() {
+ return binder;
+ }
+
+ @Override
+ public String getLocation() {
+ return binder.getLocation();
+ }
+
+ @Override
+ public void setLocation(String location) {
+ binder.setLocation(location);
+ }
+
+ @Override
+ public String getIdentifier() {
+ return binder.getIdentifier();
+ }
+
+ @Override
+ public void setIdentifier(String identifier) {
+ binder.setIdentifier(identifier);
+ }
+
+ @Override
+ public Date getDate() {
+ return binder.getDate();
+ }
+
+ @Override
+ public void setDate(Date date) {
+ binder.setDate(date);
+ }
+
+ @Override
+ public String getLicense() {
+ return binder.getLicense();
+ }
+
+ @Override
+ public void setLicense(String license) {
+ binder.setLicense(license);
+ }
+
+ @Override
+ public Attribution getAttribution() {
+ return binder.getAttribution();
+ }
+
+ @Override
+ public void setAttribution(Attribution attribution) {
+ binder.setAttribution(attribution);
+ }
+
+ @Override
+ public List<Track> getTracks() {
+ return binder.getTracks();
+ }
+
+ @Override
+ public void addTrack(Track track) {
+ binder.addTrack(track);
+ }
+
+ public void read(File inputFile) throws JAXBException {
+ binder.setPlaylist(
+ extractRootObject(
+ binder.getPlaylistClass(),
+ createUnmarshaller(
+ binder.getPlaylistClass()
+ ).unmarshal(inputFile)
+ )
+ );
+ }
+
+ @Override
+ public void write(File outputFile) throws JAXBException {
+ createMarshaller(
+ binder.getPlaylistClass()
+ ).marshal(
+ wrapPlaylist(binder),
+ outputFile
+ );
+ }
+
+ @Override
+ public OutputStream getAsStream() throws JAXBException {
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ createMarshaller(
+ binder.getPlaylistClass()
+ ).marshal(
+ wrapPlaylist(binder),
+ baos
+ );
+ return baos;
+ }
+
+ @Override
+ public String getAsString()
+ throws JAXBException, UnsupportedEncodingException
+ {
+ Charset charset = (Charset) Properties.getProperty(
+ Properties.CHARSET, Charset.class
+ );
+ ByteArrayOutputStream os = (ByteArrayOutputStream) getAsStream();
+ return os.toString(
+ charset.name()
+ );
+ }
+
+ private Marshaller createMarshaller(Class xmlRootClass) throws JAXBException {
+ JAXBContext jaxbContext = JAXBContext.newInstance(xmlRootClass);
+ Marshaller marshaller = jaxbContext.createMarshaller();
+ Charset charset = (Charset) Properties.getProperty(Properties.CHARSET, Charset.class);
+ marshaller.setProperty(
+ Marshaller.JAXB_ENCODING,
+ charset.name()
+ );
+ marshaller.setProperty(
+ Marshaller.JAXB_FORMATTED_OUTPUT,
+ Properties.getProperty(Properties.FORMATTED, Boolean.class)
+ );
+ Object standalone = Properties.getProperty(Properties.STANDALONE, Boolean.class);
+ if (Boolean.FALSE.equals(standalone)) {
+ marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
+ marshaller.setProperty(
+ XSPFConstants.XML_HEADER_NAME,
+ XSPFConstants.XML_HEADER_VALUE.replace("%CHARSET%", charset.name())
+ );
+ }
+ return marshaller;
+ }
+
+ private Unmarshaller createUnmarshaller(Class xmlRootClass) throws JAXBException {
+ JAXBContext jaxbContext = JAXBContext.newInstance(xmlRootClass);
+ return jaxbContext.createUnmarshaller();
+ }
+
+ private Object extractRootObject(Class xmlRootClass, Object unmarshallingObject) {
+ if (xmlRootClass.getAnnotation(XmlRootElement.class) != null)
+ return unmarshallingObject;
+ return unmarshallingObject instanceof JAXBElement
+ ? ((JAXBElement) unmarshallingObject).getValue()
+ : null;
+
+ }
+
+ private Object wrapPlaylist(PlaylistBinder binder) {
+ if (binder.getPlaylistClass().getAnnotation(XmlRootElement.class) != null)
+ return binder.getPlaylist();
+ return binder.wrapPlaylist();
+ }
+
+ @Override
+ public void validate() throws ValidateException {
+
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf;
+
+import java.util.List;
+
+import org.hedgecode.xml.xspf.bind.Binder;
+import org.hedgecode.xml.xspf.bind.BinderFactory;
+import org.hedgecode.xml.xspf.bind.TrackBinder;
+
+import static org.hedgecode.xml.xspf.XSPFConstants.Format;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class XMLBindTrack extends AbstractXMLBindElement implements Track {
+
+ private TrackBinder binder;
+
+ protected XMLBindTrack(TrackBinder binder) {
+ if (binder == null)
+ this.binder = BinderFactory.createTrackBinder();
+ else
+ this.binder = binder;
+ }
+
+ protected XMLBindTrack(Format format) {
+ this.binder = BinderFactory.createTrackBinder(format);
+ }
+
+ @Override
+ protected Binder getBinder() {
+ return binder;
+ }
+
+ @Override
+ public List<String> getLocations() {
+ return binder.getLocations();
+ }
+
+ @Override
+ public void addLocation(String location) {
+ binder.addLocation(location);
+ }
+
+ @Override
+ public List<String> getIdentifiers() {
+ return binder.getIdentifiers();
+ }
+
+ @Override
+ public void addIdentifier(String identifier) {
+ binder.addIdentifier(identifier);
+ }
+
+ @Override
+ public String getAlbum() {
+ return binder.getAlbum();
+ }
+
+ @Override
+ public void setAlbum(String album) {
+ binder.setAlbum(album);
+ }
+
+ @Override
+ public Integer getTrackNum() {
+ return binder.getTrackNum();
+ }
+
+ @Override
+ public void setTrackNum(Integer trackNum) {
+ binder.setTrackNum(trackNum);
+ }
+
+ @Override
+ public Integer getDuration() {
+ return binder.getDuration();
+ }
+
+ @Override
+ public void setDuration(Integer duration) {
+ binder.setDuration(duration);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf;
+
+import java.io.File;
+import java.io.UnsupportedEncodingException;
+
+import javax.xml.bind.JAXBException;
+
+import org.hedgecode.xml.xspf.validate.ValidateException;
+
+import static org.hedgecode.xml.xspf.XSPFConstants.Format;
+import static org.hedgecode.xml.xspf.XSPFConstants.Version;
+
+/**
+ * XSPF API for external applications.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class XSPF {
+
+ public static Playlist create() {
+ return create(Format.RELAX_NG);
+ }
+
+ public static Playlist create(Format format) {
+ return new XSPFPlaylist(format);
+ }
+
+ public static Playlist create(Version version) {
+ return new XSPFPlaylist(version);
+ }
+
+ public static Playlist create(String key) {
+ Format format = Format.byName(key);
+ if (format != null)
+ return create(format);
+
+ Version version = Version.byName(key);
+ if (version != null)
+ return create(version);
+
+ return null;
+ }
+
+ public static void generate(Playlist playlist, File outputFile) throws XSPFException {
+ if (playlist == null)
+ throw new XSPFException(XSPFConstants.Errors.NULL_PLAYLIST);
+ try {
+ playlist.write(outputFile);
+ } catch (JAXBException e) {
+ throw new XSPFException(XSPFConstants.Errors.BINDING_ERROR);
+ }
+ }
+
+ public static String generate(Playlist playlist) throws XSPFException {
+ if (playlist == null)
+ throw new XSPFException(XSPFConstants.Errors.NULL_PLAYLIST);
+ String result;
+ try {
+ result = playlist.getAsString();
+ } catch (JAXBException e) {
+ throw new XSPFException(XSPFConstants.Errors.BINDING_ERROR);
+ } catch (UnsupportedEncodingException e) {
+ throw new XSPFException(XSPFConstants.Errors.ENCODING_ERROR);
+ }
+ return result;
+ }
+
+ public static Playlist create(File inputFile) throws JAXBException {
+ Playlist playlist = PlaylistFactory.createPlaylist(Format.XSD);
+ playlist.read(inputFile);
+ return playlist;
+ }
+
+ public static Track createTrack(String location, String title) {
+ Track track = PlaylistFactory.createTrack();
+ track.addLocation(location);
+ track.setTitle(title);
+ return track;
+ }
+
+ public static Track addTrack(Playlist playlist, String location, String title) {
+ Track track = createTrack(location, title);
+ playlist.addTrack(track);
+ return track;
+ }
+
+ public static void addTrack(Playlist playlist, Track track) {
+ playlist.addTrack(track);
+ }
+
+ public static void addTracks(
+ Playlist playlist, Playlist tracksPlaylist) throws XSPFException
+ {
+ if (playlist == null)
+ throw new XSPFException(XSPFConstants.Errors.NULL_PLAYLIST);
+ if (tracksPlaylist != null) {
+ for (Track track : tracksPlaylist.getTracks()) {
+ playlist.addTrack(track);
+ }
+ }
+ }
+
+ public static void setProperty(String name, Object value) {
+ Properties.setProperty(name, value);
+ }
+
+ public static int validate(File inputFile) throws JAXBException {
+ int result = 0;
+ Playlist playlist = create(inputFile);
+ if (playlist != null)
+ try {
+ playlist.validate();
+ } catch (ValidateException e) {
+ result = e.getCode();
+ }
+ return result;
+ }
+
+ public static String get(int code) {
+ return null; // todo
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class XSPFAttribution implements Attribution {
+
+ private Map<String, String> idLocations;
+
+ public XSPFAttribution() {
+ idLocations = new HashMap<>();
+ }
+
+ public XSPFAttribution(Map<String, String> idLocations) {
+ this.idLocations = idLocations;
+ }
+
+ @Override
+ public Map<String, String> get() {
+ return idLocations;
+ }
+
+ @Override
+ public void add(String identifier, String location) {
+ idLocations.put(
+ identifier, location
+ );
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf;
+
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import javax.xml.namespace.QName;
+
+/**
+ * Store of library constants.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class XSPFConstants {
+
+ public static final Charset DEF_CHARSET = StandardCharsets.UTF_8;
+
+ public static final String XSD_FORMAT = "xsd";
+ public static final String RNG_FORMAT = "rng";
+
+ public static enum Format {
+
+ XSD ( XSD_FORMAT ),
+ RELAX_NG ( RNG_FORMAT );
+
+ private String formatName;
+
+ Format(String name) {
+ this.formatName = name;
+ }
+
+ public String getName() {
+ return formatName;
+ }
+
+ public static Format byName(String formatName) {
+ for (Format format : Format.values()) {
+ if (format.getName().equals(formatName))
+ return format;
+ }
+ return null;
+ }
+ }
+
+ public static final String VER_1_0_2 = "1_0.2";
+ public static final String VER_1_0_7 = "1_0.7";
+
+ public static enum Version {
+
+ V1_2 ( VER_1_0_2 ),
+ V1_7 ( VER_1_0_7 );
+
+ private String versionName;
+
+ Version(String name) {
+ this.versionName = name;
+ }
+
+ public String getName() {
+ return versionName;
+ }
+
+ public static Version byName(String versionName) {
+ for (Version version : Version.values()) {
+ if (version.getName().equals(versionName))
+ return version;
+ }
+ return null;
+ }
+ }
+
+ public static final String XSPF_VERSION = "1";
+
+ public static final QName PLAYLIST_QNAME = new QName("http://xspf.org/ns/0/", "playlist");
+
+ public static final String XML_HEADER_NAME = "com.sun.xml.internal.bind.xmlHeaders";
+ public static final String XML_HEADER_VALUE = "<?xml version=\"1.0\" encoding=\"%CHARSET%\"?>";
+
+
+ public static interface Errors {
+ public static final int NULL_PLAYLIST = 101;
+ public static final int VALIDATE_ERROR = 201;
+ public static final int BINDING_ERROR = 301;
+ public static final int ENCODING_ERROR = 401;
+ }
+
+ private XSPFConstants() {
+ throw new AssertionError(
+ "No org.hedgecode.xml.xspf.XSPFConstants instances!"
+ );
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class XSPFException extends Exception {
+
+ private static final Map<Integer, String> errors = new HashMap<Integer, String>() {
+ {
+ put(XSPFConstants.Errors.NULL_PLAYLIST, "");
+ put(XSPFConstants.Errors.VALIDATE_ERROR, "");
+ put(XSPFConstants.Errors.BINDING_ERROR, "");
+ put(XSPFConstants.Errors.ENCODING_ERROR, "");
+ }
+ };
+
+ public XSPFException(int errorCode) {
+ super(errors.get(errorCode));
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf;
+
+import java.util.List;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class XSPFExtension implements Extension {
+
+ private String application;
+ private List<Object> content;
+
+ public XSPFExtension() {
+ }
+
+ public XSPFExtension(String application, List<Object> content) {
+ this.application = application;
+ this.content = content;
+ }
+
+ @Override
+ public String getApplication() {
+ return application;
+ }
+
+ @Override
+ public List<Object> getContent() {
+ return content;
+ }
+
+ @Override
+ public void set(String application, List<Object> content) {
+ this.application = application;
+ this.content = content;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class XSPFLink implements Link {
+
+ private String rel;
+ private String content;
+
+ public XSPFLink() {
+ }
+
+ public XSPFLink(String rel, String content) {
+ this.rel = rel;
+ this.content = content;
+ }
+
+ @Override
+ public String getRel() {
+ return rel;
+ }
+
+ @Override
+ public String getContent() {
+ return content;
+ }
+
+ @Override
+ public void set(String rel, String content) {
+ this.rel = rel;
+ this.content = content;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class XSPFMeta implements Meta {
+
+ private String rel;
+ private String content;
+
+ public XSPFMeta() {
+ }
+
+ public XSPFMeta(String rel, String content) {
+ this.rel = rel;
+ this.content = content;
+ }
+
+ @Override
+ public String getRel() {
+ return rel;
+ }
+
+ @Override
+ public String getContent() {
+ return content;
+ }
+
+ @Override
+ public void set(String rel, String content) {
+ this.rel = rel;
+ this.content = content;
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf;
+
+import java.io.File;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import javax.xml.bind.JAXBException;
+
+import org.hedgecode.xml.xspf.bind.BinderFactory;
+import org.hedgecode.xml.xspf.bind.PlaylistBinder;
+import org.hedgecode.xml.xspf.validate.Validate;
+import org.hedgecode.xml.xspf.validate.ValidateException;
+import org.hedgecode.xml.xspf.validate.Validator;
+import org.hedgecode.xml.xspf.validate.ValidatorType;
+
+import static org.hedgecode.xml.xspf.XSPFConstants.Format;
+import static org.hedgecode.xml.xspf.XSPFConstants.Version;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class XSPFPlaylist implements Playlist {
+
+ protected XSPFPlaylist(Format format) {
+ this.format = format;
+ }
+
+ protected XSPFPlaylist(Version version) {
+ this.format = Format.RELAX_NG;
+ }
+
+ private Format format;
+
+ /**
+ * Human-readable title for the playlist.
+ */
+ private String title;
+
+ /**
+ * Human-readable name of the entity (author, authors, group, company, etc)
+ * that authored the playlist.
+ */
+ private String creator;
+
+ /**
+ * Human-readable comment on the playlist.
+ * This is character data, not HTML, and it may not contain markup.
+ */
+ private String annotation;
+
+ /**
+ * URI of a web page to find out more about this playlist.
+ * Likely to be homepage of the author, and would be used to find out
+ * more about the author and to find more playlists by the author.
+ */
+ private String info;
+
+ /**
+ * Source URI for this playlist.
+ */
+ @Validate(validatorType = ValidatorType.URI)
+ private String location;
+
+ /**
+ * Canonical ID for this playlist.
+ * Likely to be a hash or other location-independent name.
+ * Must be a legal URI.
+ */
+ private String identifier;
+
+ /**
+ * URI of an image to display in the absence of
+ * a playlist->trackList->image element.
+ */
+ private String image;
+
+ /**
+ * Creation date (not last-modified date) of the playlist,
+ * formatted as a XML schema dateTime.
+ * In the absence of a timezone, the element may be assumed
+ * to use Coordinated Universal Time (UTC).
+ */
+ private Date date;
+
+ /**
+ * URI of a resource that describes the license
+ * under which this playlist was released.
+ */
+ private String license;
+
+ /**
+ * An ordered list of URIs. The purpose is to satisfy licenses
+ * allowing modification but requiring attribution.
+ * If you modify such a playlist, move its playlist->location
+ * or playlist->identifier element to the top of the items
+ * in the playlist->attribution element.
+ * Such a list can grow without limit, so as a practical matter
+ * we suggest deleting ancestors more than ten generations back.
+ */
+ private Attribution attribution;
+
+ /**
+ * The link element allows XSPF to be extended
+ * without the use of XML namespaces.
+ */
+ private List<Link> links = new ArrayList<>();
+
+ /**
+ * The meta element allows metadata fields to be added to XSPF.
+ */
+ private List<Meta> metas = new ArrayList<>();
+
+ /**
+ * The extension element allows non-XSPF XML to be included in XSPF documents.
+ * The purpose is to allow nested XML, which the meta and link elements do not.
+ */
+ private List<Extension> extensions = new ArrayList<>();
+
+ /**
+ * Ordered list of track elements to be rendered.
+ * The sequence is a hint, not a requirement;
+ * renderers are advised to play tracks from top to bottom
+ * unless there is an indication otherwise.
+ */
+ private List<Track> trackList = new ArrayList<>();
+
+
+ @Override
+ public String getTitle() {
+ return title;
+ }
+
+ @Override
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ @Override
+ public String getCreator() {
+ return creator;
+ }
+
+ @Override
+ public void setCreator(String creator) {
+ this.creator = creator;
+ }
+
+ @Override
+ public String getAnnotation() {
+ return annotation;
+ }
+
+ @Override
+ public void setAnnotation(String annotation) {
+ this.annotation = annotation;
+ }
+
+ @Override
+ public String getInfo() {
+ return info;
+ }
+
+ @Override
+ public void setInfo(String info) {
+ this.info = info;
+ }
+
+ @Override
+ public String getLocation() {
+ return location;
+ }
+
+ @Override
+ public void setLocation(String location) {
+ this.location = location;
+ }
+
+ @Override
+ public String getIdentifier() {
+ return identifier;
+ }
+
+ @Override
+ public void setIdentifier(String identifier) {
+ this.identifier = identifier;
+ }
+
+ @Override
+ public String getImage() {
+ return image;
+ }
+
+ @Override
+ public void setImage(String image) {
+ this.image = image;
+ }
+
+ @Override
+ public Date getDate() {
+ return date;
+ }
+
+ @Override
+ public void setDate(Date date) {
+ this.date = date;
+ }
+
+ @Override
+ public String getLicense() {
+ return license;
+ }
+
+ @Override
+ public void setLicense(String license) {
+ this.license = license;
+ }
+
+ @Override
+ public Attribution getAttribution() {
+ return attribution;
+ }
+
+ @Override
+ public void setAttribution(Attribution attribution) {
+ this.attribution = attribution;
+ }
+
+ @Override
+ public List<Link> getLinks() {
+ return links;
+ }
+
+ @Override
+ public void addLink(Link link) {
+ links.add(link);
+ }
+
+ @Override
+ public List<Meta> getMetas() {
+ return metas;
+ }
+
+ @Override
+ public void addMeta(Meta meta) {
+ metas.add(meta);
+ }
+
+ @Override
+ public List<Extension> getExtensions() {
+ return extensions;
+ }
+
+ @Override
+ public void addExtension(Extension extension) {
+ extensions.add(extension);
+ }
+
+ @Override
+ public List<Track> getTracks() {
+ return trackList;
+ }
+
+ @Override
+ public void addTrack(Track track) {
+ trackList.add(track);
+ }
+
+ private void bind(XMLBindPlaylist bindPlaylist) {
+ bindPlaylist.setTitle(title);
+ bindPlaylist.setCreator(creator);
+ bindPlaylist.setAnnotation(annotation);
+ bindPlaylist.setInfo(info);
+ bindPlaylist.setLocation(location);
+ bindPlaylist.setIdentifier(identifier);
+ bindPlaylist.setImage(image);
+ bindPlaylist.setDate(date);
+ bindPlaylist.setLicense(license);
+ bindPlaylist.setAttribution(attribution);
+ for (Link link : links)
+ bindPlaylist.addLink(link);
+ for (Meta meta :metas)
+ bindPlaylist.addMeta(meta);
+ for (Extension extension : extensions)
+ bindPlaylist.addExtension(extension);
+ for (Track track : trackList)
+ bindPlaylist.addTrack(track);
+ }
+
+ private void unbind(XMLBindPlaylist bindPlaylist) {
+ title = bindPlaylist.getTitle();
+ creator = bindPlaylist.getCreator();
+ annotation = bindPlaylist.getAnnotation();
+ info = bindPlaylist.getInfo();
+ location = bindPlaylist.getLocation();
+ identifier = bindPlaylist.getIdentifier();
+ image = bindPlaylist.getImage();
+ date = bindPlaylist.getDate();
+ license = bindPlaylist.getLicense();
+ attribution = bindPlaylist.getAttribution();
+ links = bindPlaylist.getLinks();
+ metas = bindPlaylist.getMetas();
+ extensions = bindPlaylist.getExtensions();
+ trackList = bindPlaylist.getTracks();
+ }
+
+ @Override
+ public void read(File inputFile) throws JAXBException {
+ XMLBindPlaylist bindPlaylist = new XMLBindPlaylist(format);
+ bindPlaylist.read(inputFile);
+ unbind(bindPlaylist);
+ }
+
+ @Override
+ public void write(File outputFile) throws JAXBException {
+ XMLBindPlaylist bindPlaylist = new XMLBindPlaylist(format);
+ bind(bindPlaylist);
+ bindPlaylist.write(outputFile);
+ }
+
+ @Override
+ public OutputStream getAsStream() throws JAXBException {
+ XMLBindPlaylist bindPlaylist = new XMLBindPlaylist(format);
+ bind(bindPlaylist);
+ return bindPlaylist.getAsStream();
+ }
+
+ @Override
+ public String getAsString()
+ throws JAXBException, UnsupportedEncodingException
+ {
+ XMLBindPlaylist bindPlaylist = new XMLBindPlaylist(format);
+ bind(bindPlaylist);
+ return bindPlaylist.getAsString();
+ }
+
+
+ @Override
+ public void validate() throws ValidateException {
+ for (Field field : getClass().getFields()) {
+ if (field.isAnnotationPresent(Validate.class)) {
+ Validator validator;
+ try {
+ validator = field.getAnnotation(Validate.class).validatorType().getValidator();
+ validator.validate(
+ field.get(this)
+ );
+ } catch (ReflectiveOperationException e) {
+ throw new ValidateException(101, e.getMessage());
+ }
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class XSPFTrack implements Track {
+
+ protected XSPFTrack() {
+ }
+
+ /**
+ *
+ */
+ private List<String> locations = new ArrayList<>();
+
+ /**
+ *
+ */
+ private List<String> identifiers = new ArrayList<>();
+
+ /**
+ *
+ */
+ private String title;
+
+ /**
+ *
+ */
+ private String creator;
+
+ /**
+ *
+ */
+ private String annotation;
+
+ /**
+ *
+ */
+ private String info;
+
+ /**
+ *
+ */
+ private String image;
+
+ /**
+ *
+ */
+ private String album;
+
+ /**
+ *
+ */
+ private Integer trackNum;
+
+ /**
+ *
+ */
+ private Integer duration;
+
+ /**
+ *
+ */
+ private List<Link> links = new ArrayList<>();
+
+ /**
+ *
+ */
+ private List<Meta> metas = new ArrayList<>();
+
+ /**
+ *
+ */
+ private List<Extension> extensions = new ArrayList<>();
+
+ @Override
+ public List<String> getLocations() {
+ return locations;
+ }
+
+ @Override
+ public void addLocation(String location) {
+ locations.add(location);
+ }
+
+ @Override
+ public List<String> getIdentifiers() {
+ return identifiers;
+ }
+
+ @Override
+ public void addIdentifier(String identifier) {
+ identifiers.add(identifier);
+ }
+
+ @Override
+ public String getTitle() {
+ return title;
+ }
+
+ @Override
+ public void setTitle(String title) {
+ this.title = title;
+ }
+
+ @Override
+ public String getCreator() {
+ return creator;
+ }
+
+ @Override
+ public void setCreator(String creator) {
+ this.creator = creator;
+ }
+
+ @Override
+ public String getAnnotation() {
+ return annotation;
+ }
+
+ @Override
+ public void setAnnotation(String annotation) {
+ this.annotation = annotation;
+ }
+
+ @Override
+ public String getInfo() {
+ return info;
+ }
+
+ @Override
+ public void setInfo(String info) {
+ this.info = info;
+ }
+
+ @Override
+ public String getImage() {
+ return image;
+ }
+
+ @Override
+ public void setImage(String image) {
+ this.image = image;
+ }
+
+ @Override
+ public String getAlbum() {
+ return album;
+ }
+
+ @Override
+ public void setAlbum(String album) {
+ this.album = album;
+ }
+
+ @Override
+ public Integer getTrackNum() {
+ return trackNum;
+ }
+
+ @Override
+ public void setTrackNum(Integer trackNum) {
+ this.trackNum = trackNum;
+ }
+
+ @Override
+ public Integer getDuration() {
+ return duration;
+ }
+
+ @Override
+ public void setDuration(Integer duration) {
+ this.duration = duration;
+ }
+
+ @Override
+ public List<Link> getLinks() {
+ return links;
+ }
+
+ @Override
+ public void addLink(Link link) {
+ links.add(link);
+ }
+
+ @Override
+ public List<Meta> getMetas() {
+ return metas;
+ }
+
+ @Override
+ public void addMeta(Meta meta) {
+ metas.add(meta);
+ }
+
+ @Override
+ public List<Extension> getExtensions() {
+ return extensions;
+ }
+
+ @Override
+ public void addExtension(Extension extension) {
+ extensions.add(extension);
+ }
+
+ protected void bind(XMLBindTrack bindTrack) {
+ for (String location : locations)
+ bindTrack.addLocation(location);
+ for (String identifier : identifiers)
+ bindTrack.addIdentifier(identifier);
+ bindTrack.setTitle(title);
+ bindTrack.setCreator(creator);
+ bindTrack.setAnnotation(annotation);
+ bindTrack.setInfo(info);
+ bindTrack.setImage(image);
+ bindTrack.setAlbum(album);
+ bindTrack.setTrackNum(trackNum);
+ bindTrack.setDuration(duration);
+ for (Link link : links)
+ bindTrack.addLink(link);
+ for (Meta meta :metas)
+ bindTrack.addMeta(meta);
+ for (Extension extension : extensions)
+ bindTrack.addExtension(extension);
+ }
+
+ protected void unbind(XMLBindTrack bindTrack) {
+ locations = bindTrack.getLocations();
+ identifiers = bindTrack.getIdentifiers();
+ title = bindTrack.getTitle();
+ creator = bindTrack.getCreator();
+ annotation = bindTrack.getAnnotation();
+ info = bindTrack.getInfo();
+ image = bindTrack.getImage();
+ album = bindTrack.getAlbum();
+ trackNum = bindTrack.getTrackNum();
+ duration = bindTrack.getDuration();
+ links = bindTrack.getLinks();
+ metas = bindTrack.getMetas();
+ extensions = bindTrack.getExtensions();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf.bind;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.hedgecode.xml.xspf.PlaylistFactory;
+import org.hedgecode.xml.xspf.rng.Annotation;
+import org.hedgecode.xml.xspf.rng.Creator;
+import org.hedgecode.xml.xspf.rng.Extension;
+import org.hedgecode.xml.xspf.rng.Image;
+import org.hedgecode.xml.xspf.rng.Info;
+import org.hedgecode.xml.xspf.rng.Link;
+import org.hedgecode.xml.xspf.rng.Meta;
+import org.hedgecode.xml.xspf.rng.ObjectFactory;
+import org.hedgecode.xml.xspf.rng.Title;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public abstract class AbstractRNGBinder implements Binder {
+
+ protected static final ObjectFactory RNG_FACTORY = new ObjectFactory();
+
+ protected abstract Object getElement(Class elementClass);
+
+ protected abstract List<Object> getElements(Class elementClass);
+
+ protected abstract List<Object> getAllElements();
+
+ @Override
+ public String getTitle() {
+ Title titleElement = (Title) getElement(Title.class);
+ return titleElement != null ? titleElement.getContent() : null;
+ }
+
+ @Override
+ public void setTitle(String title) {
+ Title titleElement = (Title) getElement(Title.class);
+ if (titleElement != null)
+ getAllElements().remove(titleElement);
+ if (title != null) {
+ titleElement = RNG_FACTORY.createTitle();
+ titleElement.setContent(title);
+ getAllElements().add(titleElement);
+ }
+ }
+
+ @Override
+ public String getCreator() {
+ Creator creatorElement = (Creator) getElement(Creator.class);
+ return creatorElement != null ? creatorElement.getContent() : null;
+ }
+
+ @Override
+ public void setCreator(String creator) {
+ Creator creatorElement = (Creator) getElement(Creator.class);
+ if (creatorElement != null)
+ getAllElements().remove(creatorElement);
+ if (creator != null) {
+ creatorElement = RNG_FACTORY.createCreator();
+ creatorElement.setContent(creator);
+ getAllElements().add(creatorElement);
+ }
+ }
+
+ @Override
+ public String getAnnotation() {
+ Annotation annotationElement = (Annotation) getElement(Annotation.class);
+ return annotationElement != null ? annotationElement.getContent() : null;
+ }
+
+ @Override
+ public void setAnnotation(String annotation) {
+ Annotation annotationElement = (Annotation) getElement(Annotation.class);
+ if (annotationElement != null)
+ getAllElements().remove(annotationElement);
+ if (annotation != null) {
+ annotationElement = RNG_FACTORY.createAnnotation();
+ annotationElement.setContent(annotation);
+ getAllElements().add(annotationElement);
+ }
+ }
+
+ @Override
+ public String getInfo() {
+ Info infoElement = (Info) getElement(Info.class);
+ return infoElement != null ? infoElement.getValue() : null;
+ }
+
+ @Override
+ public void setInfo(String info) {
+ Info infoElement = (Info) getElement(Info.class);
+ if (infoElement != null)
+ getAllElements().remove(infoElement);
+ if (info != null) {
+ infoElement = RNG_FACTORY.createInfo();
+ infoElement.setValue(info);
+ getAllElements().add(infoElement);
+ }
+ }
+
+ @Override
+ public String getImage() {
+ Image imageElement = (Image) getElement(Image.class);
+ return imageElement != null ? imageElement.getValue() : null;
+ }
+
+ @Override
+ public void setImage(String image) {
+ Image imageElement = (Image) getElement(Image.class);
+ if (imageElement != null)
+ getAllElements().remove(imageElement);
+ if (image != null) {
+ imageElement = RNG_FACTORY.createImage();
+ imageElement.setValue(image);
+ getAllElements().add(imageElement);
+ }
+ }
+
+ @Override
+ public List<org.hedgecode.xml.xspf.Link> getLinks() {
+ List<org.hedgecode.xml.xspf.Link> links = new ArrayList<>();
+ for (Object element : getElements(Link.class)) {
+ Link linkElement = (Link) element;
+ links.add(
+ PlaylistFactory.createLink(
+ linkElement.getRel(), linkElement.getValue()
+ )
+ );
+ }
+ return links;
+ }
+
+ @Override
+ public void addLink(org.hedgecode.xml.xspf.Link link) {
+ if (link != null) {
+ Link linkElement = RNG_FACTORY.createLink();
+ linkElement.setRel(link.getRel());
+ linkElement.setValue(link.getContent());
+ getAllElements().add(linkElement);
+ }
+ }
+
+ @Override
+ public List<org.hedgecode.xml.xspf.Meta> getMetas() {
+ List<org.hedgecode.xml.xspf.Meta> metas = new ArrayList<>();
+ for (Object element : getElements(Meta.class)) {
+ Meta metaElement = (Meta) element;
+ metas.add(
+ PlaylistFactory.createMeta(
+ metaElement.getRel(), metaElement.getContent()
+ )
+ );
+ }
+ return metas;
+ }
+
+ @Override
+ public void addMeta(org.hedgecode.xml.xspf.Meta meta) {
+ if (meta != null) {
+ Meta metaElement = RNG_FACTORY.createMeta();
+ metaElement.setRel(meta.getRel());
+ metaElement.setContent(meta.getContent());
+ getAllElements().add(metaElement);
+ }
+ }
+
+ @Override
+ public List<org.hedgecode.xml.xspf.Extension> getExtensions() {
+ List<org.hedgecode.xml.xspf.Extension> extensions = new ArrayList<>();
+ for (Object element : getElements(Extension.class)) {
+ Extension extensionElement = (Extension) element;
+ extensions.add(
+ PlaylistFactory.createExtension(
+ extensionElement.getApplication(), extensionElement.getContent()
+ )
+ );
+ }
+ return extensions;
+ }
+
+ @Override
+ public void addExtension(org.hedgecode.xml.xspf.Extension extension) {
+ if (extension != null) {
+ Extension extensionElement = RNG_FACTORY.createExtension();
+ extensionElement.setApplication(extension.getApplication());
+ extensionElement.getContent().addAll(extension.getContent());
+ getAllElements().add(extensionElement);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf.bind;
+
+import org.hedgecode.xml.xspf.xsd.ObjectFactory;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public abstract class AbstractXSDBinder implements Binder {
+
+ protected static final ObjectFactory XSD_FACTORY = new ObjectFactory();
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf.bind;
+
+import java.util.List;
+
+import org.hedgecode.xml.xspf.Extension;
+import org.hedgecode.xml.xspf.Link;
+import org.hedgecode.xml.xspf.Meta;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface Binder {
+
+ String getTitle();
+
+ void setTitle(String title);
+
+ String getCreator();
+
+ void setCreator(String creator);
+
+ String getAnnotation();
+
+ void setAnnotation(String annotation);
+
+ String getInfo();
+
+ void setInfo(String info);
+
+ String getImage();
+
+ void setImage(String image);
+
+ List<Link> getLinks();
+
+ void addLink(Link link);
+
+ List<Meta> getMetas();
+
+ void addMeta(Meta meta);
+
+ List<Extension> getExtensions();
+
+ void addExtension(Extension extension);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf.bind;
+
+import org.hedgecode.xml.xspf.rng.Track;
+import org.hedgecode.xml.xspf.xsd.TrackType;
+
+import static org.hedgecode.xml.xspf.XSPFConstants.Format;
+
+/**
+ * Playlist/Track Binder Factory.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public final class BinderFactory {
+
+ public static PlaylistBinder createPlaylistBinder() {
+ return getDefaultPlaylistBinder();
+ }
+
+ public static PlaylistBinder createPlaylistBinder(Format format) {
+ switch(format) {
+ case RELAX_NG:
+ return new RNGPlaylistBinder();
+ case XSD:
+ return new XSDPlaylistBinder();
+ default:
+ return getDefaultPlaylistBinder();
+ }
+ }
+
+ public static TrackBinder createTrackBinder() {
+ return getDefaultTrackBinder();
+ }
+
+ public static TrackBinder createTrackBinder(Format format) {
+ switch(format) {
+ case RELAX_NG:
+ return new RNGTrackBinder();
+ case XSD:
+ return new XSDTrackBinder();
+ default:
+ return getDefaultTrackBinder();
+ }
+ }
+
+ public static TrackBinder createTrackBinder(Track track) {
+ return new RNGTrackBinder(track);
+ }
+
+ public static TrackBinder createTrackBinder(TrackType trackType) {
+ return new XSDTrackBinder(trackType);
+ }
+
+ private static PlaylistBinder getDefaultPlaylistBinder() {
+ return new RNGPlaylistBinder();
+ }
+
+ private static TrackBinder getDefaultTrackBinder() {
+ return new RNGTrackBinder();
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf.bind;
+
+import java.util.Date;
+import java.util.List;
+
+import javax.xml.bind.JAXBElement;
+
+import org.hedgecode.xml.xspf.Attribution;
+import org.hedgecode.xml.xspf.Extension;
+import org.hedgecode.xml.xspf.Link;
+import org.hedgecode.xml.xspf.Meta;
+import org.hedgecode.xml.xspf.Track;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface PlaylistBinder extends Binder {
+
+ String getPackageName();
+
+ Class getPlaylistClass();
+
+ Object getPlaylist();
+
+ void setPlaylist(Object playlist);
+
+ public JAXBElement wrapPlaylist();
+
+ String getLocation();
+
+ void setLocation(String location);
+
+ String getIdentifier();
+
+ void setIdentifier(String identifier);
+
+ Date getDate();
+
+ void setDate(Date date);
+
+ String getLicense();
+
+ void setLicense(String license);
+
+ Attribution getAttribution();
+
+ void setAttribution(Attribution attribution);
+
+ List<Track> getTracks();
+
+ void addTrack(Track track);
+
+ String getVersion();
+
+ void setVersion(String version);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf.bind;
+
+import java.util.ArrayList;
+import java.util.GregorianCalendar;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.datatype.DatatypeConfigurationException;
+import javax.xml.datatype.DatatypeFactory;
+import javax.xml.datatype.XMLGregorianCalendar;
+import javax.xml.namespace.QName;
+
+import org.hedgecode.xml.xspf.PlaylistFactory;
+import org.hedgecode.xml.xspf.XSPFConstants;
+import org.hedgecode.xml.xspf.rng.Attribution;
+import org.hedgecode.xml.xspf.rng.Date;
+import org.hedgecode.xml.xspf.rng.Identifier;
+import org.hedgecode.xml.xspf.rng.License;
+import org.hedgecode.xml.xspf.rng.Location;
+import org.hedgecode.xml.xspf.rng.Playlist;
+import org.hedgecode.xml.xspf.rng.Track;
+import org.hedgecode.xml.xspf.rng.TrackList;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class RNGPlaylistBinder extends AbstractRNGBinder implements PlaylistBinder {
+
+ private Playlist rngPlaylist;
+
+ public RNGPlaylistBinder() {
+ this.rngPlaylist = RNG_FACTORY.createPlaylist();
+ }
+
+ public RNGPlaylistBinder(Playlist rngPlaylist) {
+ this.rngPlaylist = rngPlaylist;
+ }
+
+ @Override
+ protected Object getElement(Class elementClass) {
+ for (Object element : rngPlaylist.getTitleOrCreatorOrAnnotation()) {
+ if (element.getClass().equals(elementClass))
+ return element;
+ }
+ return null;
+ }
+
+ @Override
+ protected List<Object> getElements(Class elementClass) {
+ List<Object> elements = new ArrayList<>();
+ for (Object element : rngPlaylist.getTitleOrCreatorOrAnnotation()) {
+ if (element.getClass().equals(elementClass))
+ elements.add(element);
+ }
+ return elements;
+ }
+
+ @Override
+ protected List<Object> getAllElements() {
+ return rngPlaylist.getTitleOrCreatorOrAnnotation();
+ }
+
+ @Override
+ public String getPackageName() {
+ return rngPlaylist.getClass().getPackage().getName();
+ }
+
+ @Override
+ public Class getPlaylistClass() {
+ return rngPlaylist.getClass();
+ }
+
+ @Override
+ public Object getPlaylist() {
+ return rngPlaylist;
+ }
+
+ @Override
+ public void setPlaylist(Object playlist) {
+ if (playlist instanceof Playlist)
+ this.rngPlaylist = (Playlist) playlist;
+ }
+
+ @Override
+ public JAXBElement wrapPlaylist() {
+ return new JAXBElement<>(
+ XSPFConstants.PLAYLIST_QNAME,
+ Playlist.class,
+ rngPlaylist
+ );
+ }
+
+ @Override
+ public String getLocation() {
+ Location locationElement = (Location) getElement(Location.class);
+ return locationElement != null ? locationElement.getValue() : null;
+ }
+
+ @Override
+ public void setLocation(String location) {
+ Location locationElement = (Location) getElement(Location.class);
+ if (locationElement != null)
+ getAllElements().remove(locationElement);
+ if (location != null) {
+ locationElement = RNG_FACTORY.createLocation();
+ locationElement.setValue(location);
+ getAllElements().add(locationElement);
+ }
+ }
+
+ @Override
+ public String getIdentifier() {
+ Identifier identifierElement = (Identifier) getElement(Identifier.class);
+ return identifierElement != null ? identifierElement.getValue() : null;
+ }
+
+ @Override
+ public void setIdentifier(String identifier) {
+ Identifier identifierElement = (Identifier) getElement(Identifier.class);
+ if (identifierElement != null)
+ getAllElements().remove(identifierElement);
+ if (identifier != null) {
+ identifierElement = RNG_FACTORY.createIdentifier();
+ identifierElement.setValue(identifier);
+ getAllElements().add(identifierElement);
+ }
+ }
+
+ @Override
+ public java.util.Date getDate() {
+ Date dateElement = (Date) getElement(Date.class);
+ return dateElement != null && dateElement.getValue() != null
+ ? dateElement.getValue().toGregorianCalendar().getTime()
+ : null;
+ }
+
+ @Override
+ public void setDate(java.util.Date date) {
+ Date dateElement = (Date) getElement(Date.class);
+ if (dateElement != null)
+ getAllElements().remove(dateElement);
+ if (date != null) {
+ dateElement = RNG_FACTORY.createDate();
+ GregorianCalendar gCalendar = new GregorianCalendar();
+ gCalendar.setTime(date);
+ XMLGregorianCalendar xmlCalendar = null;
+ try {
+ xmlCalendar = DatatypeFactory.newInstance().newXMLGregorianCalendar(gCalendar);
+ } catch (DatatypeConfigurationException ignored) {}
+ dateElement.setValue(xmlCalendar);
+ getAllElements().add(dateElement);
+ }
+ }
+
+ @Override
+ public String getLicense() {
+ License licenseElement = (License) getElement(License.class);
+ return licenseElement != null ? licenseElement.getValue() : null;
+ }
+
+ @Override
+ public void setLicense(String license) {
+ License licenseElement = (License) getElement(License.class);
+ if (licenseElement != null)
+ getAllElements().remove(licenseElement);
+ if (license != null) {
+ licenseElement = RNG_FACTORY.createLicense();
+ licenseElement.setValue(license);
+ getAllElements().add(licenseElement);
+ }
+ }
+
+ @Override
+ public org.hedgecode.xml.xspf.Attribution getAttribution() {
+ Attribution attributionElement = (Attribution) getElement(Attribution.class);
+ if (attributionElement != null) {
+ org.hedgecode.xml.xspf.Attribution attribution = PlaylistFactory.createAttribution();
+ String identifier = null, location = null;
+ for (Object element : attributionElement.getIdentifierOrLocation()) {
+
+ if (element.getClass().equals(Identifier.class))
+ identifier = ((Identifier) element).getValue();
+ else if (element.getClass().equals(Location.class))
+ location = ((Location) element).getValue();
+
+ if (identifier != null && location != null) {
+ attribution.add(identifier, location);
+ identifier = null;
+ location = null;
+ }
+ }
+ return attribution;
+ }
+ return null;
+ }
+
+ @Override
+ public void setAttribution(org.hedgecode.xml.xspf.Attribution attribution) {
+ Attribution attributionElement = (Attribution) getElement(Attribution.class);
+ if (attributionElement != null)
+ getAllElements().remove(attributionElement);
+ if (attribution != null) {
+ attributionElement = RNG_FACTORY.createAttribution();
+ for (Map.Entry<String, String> element : attribution.get().entrySet()) {
+ Location location = RNG_FACTORY.createLocation();
+ location.setValue(element.getKey());
+ Identifier identifier = RNG_FACTORY.createIdentifier();
+ identifier.setValue(element.getValue());
+ attributionElement.getIdentifierOrLocation().add(location);
+ attributionElement.getIdentifierOrLocation().add(identifier);
+ }
+ getAllElements().add(attributionElement);
+ }
+ }
+
+ @Override
+ public List<org.hedgecode.xml.xspf.Track> getTracks() {
+ List<org.hedgecode.xml.xspf.Track> tracks = new ArrayList<>();
+ TrackList traclListElement = (TrackList) getElement(TrackList.class);
+ if (traclListElement != null) {
+ for (Track track : traclListElement.getTrack()) {
+ tracks.add(
+ PlaylistFactory.createTrack(
+ BinderFactory.createTrackBinder(track)
+ )
+ );
+ }
+ }
+ return tracks;
+ }
+
+ @Override
+ public void addTrack(org.hedgecode.xml.xspf.Track track) {
+ if (track != null) {
+ TrackList trackListElement = (TrackList) getElement(TrackList.class);
+ if (trackListElement == null) {
+ trackListElement = RNG_FACTORY.createTrackList();
+ getAllElements().add(trackListElement);
+ }
+
+ Track trackElement = RNG_FACTORY.createTrack();
+ PlaylistFactory.bindTrack(
+ track,
+ BinderFactory.createTrackBinder(trackElement)
+ );
+
+ trackListElement.getTrack().add(
+ trackElement
+ );
+ }
+ }
+
+ @Override
+ public String getVersion() {
+ return rngPlaylist.getVersion();
+ }
+
+ @Override
+ public void setVersion(String version) {
+ rngPlaylist.setVersion(version);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf.bind;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.hedgecode.xml.xspf.rng.Album;
+import org.hedgecode.xml.xspf.rng.Duration;
+import org.hedgecode.xml.xspf.rng.Identifier;
+import org.hedgecode.xml.xspf.rng.Location;
+import org.hedgecode.xml.xspf.rng.Track;
+import org.hedgecode.xml.xspf.rng.TrackNum;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class RNGTrackBinder extends AbstractRNGBinder implements TrackBinder {
+
+ private Track rngTrack;
+
+ public RNGTrackBinder() {
+ this.rngTrack = RNG_FACTORY.createTrack();
+ }
+
+ public RNGTrackBinder(Track rngTrack) {
+ this.rngTrack = rngTrack;
+ }
+
+ @Override
+ protected Object getElement(Class elementClass) {
+ for (Object element : rngTrack.getLocationOrIdentifierOrTitle()) {
+ if (element.getClass().equals(elementClass))
+ return element;
+ }
+ return null;
+ }
+
+ @Override
+ protected List<Object> getElements(Class elementClass) {
+ List<Object> elements = new ArrayList<>();
+ for (Object element : rngTrack.getLocationOrIdentifierOrTitle()) {
+ if (element.getClass().equals(elementClass))
+ elements.add(element);
+ }
+ return elements;
+ }
+
+ @Override
+ protected List<Object> getAllElements() {
+ return rngTrack.getLocationOrIdentifierOrTitle();
+ }
+
+ @Override
+ public List<String> getLocations() {
+ List<String> locations = new ArrayList<>();
+ for (Object element : getElements(Location.class)) {
+ Location locationElement = (Location) element;
+ locations.add(
+ locationElement.getValue()
+ );
+ }
+ return locations;
+ }
+
+ @Override
+ public void addLocation(String location) {
+ if (location != null) {
+ Location locationElement = RNG_FACTORY.createLocation();
+ locationElement.setValue(location);
+ getAllElements().add(locationElement);
+ }
+ }
+
+ @Override
+ public List<String> getIdentifiers() {
+ List<String> identifiers = new ArrayList<>();
+ for (Object element : getElements(Identifier.class)) {
+ Identifier identifierElement = (Identifier) element;
+ identifiers.add(
+ identifierElement.getValue()
+ );
+ }
+ return identifiers;
+ }
+
+ @Override
+ public void addIdentifier(String identifier) {
+ if (identifier != null) {
+ Identifier identifierElement = RNG_FACTORY.createIdentifier();
+ identifierElement.setValue(identifier);
+ getAllElements().add(identifierElement);
+ }
+ }
+
+ @Override
+ public String getAlbum() {
+ Album albumElement = (Album) getElement(Album.class);
+ return albumElement != null ? albumElement.getContent() : null;
+ }
+
+ @Override
+ public void setAlbum(String album) {
+ Album albumElement = (Album) getElement(Album.class);
+ if (albumElement != null)
+ getAllElements().remove(albumElement);
+ if (album != null) {
+ albumElement = RNG_FACTORY.createAlbum();
+ albumElement.setContent(album);
+ getAllElements().add(albumElement);
+ }
+ }
+
+ @Override
+ public Integer getTrackNum() {
+ TrackNum trackNumElement = (TrackNum) getElement(TrackNum.class);
+ return trackNumElement != null && trackNumElement.getValue() != null
+ ? trackNumElement.getValue().intValue()
+ : null;
+ }
+
+ @Override
+ public void setTrackNum(Integer trackNum) {
+ TrackNum trackNumElement = (TrackNum) getElement(TrackNum.class);
+ if (trackNumElement != null)
+ getAllElements().remove(trackNumElement);
+ if (trackNum != null) {
+ trackNumElement = RNG_FACTORY.createTrackNum();
+ trackNumElement.setValue(
+ BigInteger.valueOf(trackNum)
+ );
+ getAllElements().add(trackNumElement);
+ }
+ }
+
+ @Override
+ public Integer getDuration() {
+ Duration durationElement = (Duration) getElement(Duration.class);
+ return durationElement != null && durationElement.getValue() != null
+ ? durationElement.getValue().intValue()
+ : null;
+ }
+
+ @Override
+ public void setDuration(Integer duration) {
+ Duration durationElement = (Duration) getElement(Duration.class);
+ if (durationElement != null)
+ getAllElements().remove(durationElement);
+ if (duration != null) {
+ durationElement = RNG_FACTORY.createDuration();
+ durationElement.setValue(
+ BigInteger.valueOf(duration)
+ );
+ getAllElements().add(durationElement);
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf.bind;
+
+import java.util.List;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface TrackBinder extends Binder {
+
+ List<String> getLocations();
+
+ void addLocation(String location);
+
+ List<String> getIdentifiers();
+
+ void addIdentifier(String identifier);
+
+ String getAlbum();
+
+ void setAlbum(String album);
+
+ Integer getTrackNum();
+
+ void setTrackNum(Integer trackNum);
+
+ Integer getDuration();
+
+ void setDuration(Integer duration);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf.bind;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.List;
+import java.util.Map;
+
+import javax.xml.bind.JAXBElement;
+import javax.xml.datatype.DatatypeConfigurationException;
+import javax.xml.datatype.DatatypeFactory;
+import javax.xml.datatype.XMLGregorianCalendar;
+import javax.xml.namespace.QName;
+
+import org.hedgecode.xml.xspf.Attribution;
+import org.hedgecode.xml.xspf.Extension;
+import org.hedgecode.xml.xspf.Link;
+import org.hedgecode.xml.xspf.Meta;
+import org.hedgecode.xml.xspf.PlaylistFactory;
+import org.hedgecode.xml.xspf.Track;
+import org.hedgecode.xml.xspf.xsd.ExtensionType;
+import org.hedgecode.xml.xspf.xsd.LinkType;
+import org.hedgecode.xml.xspf.xsd.MetaType;
+import org.hedgecode.xml.xspf.xsd.PlaylistType;
+import org.hedgecode.xml.xspf.xsd.TrackType;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class XSDPlaylistBinder extends AbstractXSDBinder implements PlaylistBinder {
+
+ private static final String REF_LOCATION_NAME = "location";
+ private static final String REF_IDENTIFIER_NAME = "identifier";
+
+ private PlaylistType xsdPlaylist;
+
+ public XSDPlaylistBinder() {
+ this.xsdPlaylist = XSD_FACTORY.createPlaylistType();
+ }
+
+ public XSDPlaylistBinder(PlaylistType xsdPlaylist) {
+ this.xsdPlaylist = xsdPlaylist;
+ }
+
+ @Override
+ public String getPackageName() {
+ return xsdPlaylist.getClass().getPackage().getName();
+ }
+
+ @Override
+ public Class getPlaylistClass() {
+ return xsdPlaylist.getClass();
+ }
+
+ @Override
+ public Object getPlaylist() {
+ return xsdPlaylist;
+ }
+
+ @Override
+ public void setPlaylist(Object playlist) {
+ if (playlist instanceof PlaylistType)
+ this.xsdPlaylist = (PlaylistType) playlist;
+ }
+
+ @Override
+ public JAXBElement wrapPlaylist() {
+ return XSD_FACTORY.createPlaylist(xsdPlaylist);
+ }
+
+ @Override
+ public String getTitle() {
+ return xsdPlaylist.getTitle();
+ }
+
+ @Override
+ public void setTitle(String title) {
+ xsdPlaylist.setTitle(title);
+ }
+
+ @Override
+ public String getCreator() {
+ return xsdPlaylist.getCreator();
+ }
+
+ @Override
+ public void setCreator(String creator) {
+ xsdPlaylist.setCreator(creator);
+ }
+
+ @Override
+ public String getAnnotation() {
+ return xsdPlaylist.getAnnotation();
+ }
+
+ @Override
+ public void setAnnotation(String annotation) {
+ xsdPlaylist.setAnnotation(annotation);
+ }
+
+ @Override
+ public String getInfo() {
+ return xsdPlaylist.getInfo();
+ }
+
+ @Override
+ public void setInfo(String info) {
+ xsdPlaylist.setInfo(info);
+ }
+
+ @Override
+ public String getLocation() {
+ return xsdPlaylist.getLocation();
+ }
+
+ @Override
+ public void setLocation(String location) {
+ xsdPlaylist.setLocation(location);
+ }
+
+ @Override
+ public String getIdentifier() {
+ return xsdPlaylist.getIdentifier();
+ }
+
+ @Override
+ public void setIdentifier(String identifier) {
+ xsdPlaylist.setIdentifier(identifier);
+ }
+
+ @Override
+ public String getImage() {
+ return xsdPlaylist.getImage();
+ }
+
+ @Override
+ public void setImage(String image) {
+ xsdPlaylist.setImage(image);
+ }
+
+ @Override
+ public Date getDate() {
+ XMLGregorianCalendar calendar = xsdPlaylist.getDate();
+ if (calendar != null)
+ return calendar.toGregorianCalendar().getTime();
+ return null;
+ }
+
+ @Override
+ public void setDate(Date date) {
+ XMLGregorianCalendar xmlCalendar = null;
+ if (date != null) {
+ GregorianCalendar gCalendar = new GregorianCalendar();
+ gCalendar.setTime(date);
+ try {
+ xmlCalendar = DatatypeFactory.newInstance().newXMLGregorianCalendar(gCalendar);
+ } catch (DatatypeConfigurationException ignored) {}
+ }
+ xsdPlaylist.setDate(xmlCalendar);
+ }
+
+ @Override
+ public String getLicense() {
+ return xsdPlaylist.getLicense();
+ }
+
+ @Override
+ public void setLicense(String license) {
+ xsdPlaylist.setLicense(license);
+ }
+
+ @Override
+ public Attribution getAttribution() {
+ if (xsdPlaylist.getAttribution() != null) {
+ List<JAXBElement<String>> elements = xsdPlaylist.getAttribution().getIdentifierOrLocation();
+ Attribution attribution = PlaylistFactory.createAttribution();
+ String identifier = null, location = null;
+ for (JAXBElement<String> element : elements) {
+
+ if (REF_IDENTIFIER_NAME.equals(element.getName().getLocalPart()))
+ identifier = element.getValue();
+ else if (REF_LOCATION_NAME.equals(element.getName().getLocalPart()))
+ location = element.getValue();
+
+ if (identifier != null && location != null) {
+ attribution.add(identifier, location);
+ identifier = null;
+ location = null;
+ }
+ }
+ return attribution;
+ }
+ return null;
+ }
+
+ @Override
+ public void setAttribution(Attribution attribution) {
+ if (attribution != null) {
+ if (xsdPlaylist.getAttribution() == null) {
+ xsdPlaylist.setAttribution(
+ XSD_FACTORY.createAttributionType()
+ );
+ }
+ for (Map.Entry<String, String> element : attribution.get().entrySet()) {
+ xsdPlaylist.getAttribution().getIdentifierOrLocation().add(
+ XSD_FACTORY.createAttributionTypeIdentifier(element.getKey())
+ );
+ xsdPlaylist.getAttribution().getIdentifierOrLocation().add(
+ XSD_FACTORY.createAttributionTypeLocation(element.getValue())
+ );
+ }
+ }
+ }
+
+ @Override
+ public List<Link> getLinks() {
+ List<Link> links = new ArrayList<>();
+ for (LinkType link : xsdPlaylist.getLink()) {
+ links.add(
+ PlaylistFactory.createLink(link.getRel(), link.getValue())
+ );
+ }
+ return links;
+ }
+
+ @Override
+ public void addLink(Link link) {
+ if (link != null) {
+ LinkType linkType = XSD_FACTORY.createLinkType();
+ linkType.setRel(link.getRel());
+ linkType.setValue(link.getContent());
+ xsdPlaylist.getLink().add(
+ linkType
+ );
+ }
+ }
+
+ @Override
+ public List<Meta> getMetas() {
+ List<Meta> metas = new ArrayList<>();
+ for (MetaType meta : xsdPlaylist.getMeta()) {
+ metas.add(
+ PlaylistFactory.createMeta(meta.getRel(), meta.getValue())
+ );
+ }
+ return metas;
+ }
+
+ @Override
+ public void addMeta(Meta meta) {
+ if (meta != null) {
+ MetaType metaType = XSD_FACTORY.createMetaType();
+ metaType.setRel(meta.getRel());
+ metaType.setValue(meta.getContent());
+ xsdPlaylist.getMeta().add(
+ metaType
+ );
+ }
+ }
+
+ @Override
+ public List<Extension> getExtensions() {
+ List<Extension> extensions = new ArrayList<>();
+ for (ExtensionType extension : xsdPlaylist.getExtension()) {
+ extensions.add(
+ PlaylistFactory.createExtension(
+ extension.getApplication(), extension.getContent()
+ )
+ );
+ }
+ return extensions;
+ }
+
+ @Override
+ public void addExtension(Extension extension) {
+ if (extension != null) {
+ ExtensionType extensionType = XSD_FACTORY.createExtensionType();
+ extensionType.setApplication(extension.getApplication());
+ extensionType.getContent().addAll(extension.getContent());
+ xsdPlaylist.getExtension().add(
+ extensionType
+ );
+ }
+ }
+
+ @Override
+ public List<Track> getTracks() {
+ List<Track> tracks = new ArrayList<>();
+ if (xsdPlaylist.getTrackList() != null) {
+ for (TrackType track : xsdPlaylist.getTrackList().getTrack()) {
+ tracks.add(
+ PlaylistFactory.createTrack(
+ BinderFactory.createTrackBinder(track)
+ )
+ );
+ }
+ }
+ return tracks;
+ }
+
+ @Override
+ public void addTrack(Track track) {
+ if (track != null) {
+ if (xsdPlaylist.getTrackList() == null) {
+ xsdPlaylist.setTrackList(
+ XSD_FACTORY.createTrackListType()
+ );
+ }
+ TrackType trackType = XSD_FACTORY.createTrackType();
+
+ PlaylistFactory.bindTrack(
+ track,
+ BinderFactory.createTrackBinder(trackType)
+ );
+
+ xsdPlaylist.getTrackList().getTrack().add(
+ trackType
+ );
+ }
+ }
+
+ @Override
+ public String getVersion() {
+ return xsdPlaylist.getVersion();
+ }
+
+ @Override
+ public void setVersion(String version) {
+ xsdPlaylist.setVersion(version);
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf.bind;
+
+import java.math.BigInteger;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.hedgecode.xml.xspf.Extension;
+import org.hedgecode.xml.xspf.Link;
+import org.hedgecode.xml.xspf.Meta;
+import org.hedgecode.xml.xspf.PlaylistFactory;
+import org.hedgecode.xml.xspf.xsd.ExtensionType;
+import org.hedgecode.xml.xspf.xsd.LinkType;
+import org.hedgecode.xml.xspf.xsd.MetaType;
+import org.hedgecode.xml.xspf.xsd.TrackType;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class XSDTrackBinder extends AbstractXSDBinder implements TrackBinder {
+
+ private TrackType xsdTrack;
+
+ public XSDTrackBinder() {
+ this.xsdTrack = XSD_FACTORY.createTrackType();
+ }
+
+ public XSDTrackBinder(TrackType xsdTrack) {
+ this.xsdTrack = xsdTrack;
+ }
+
+ public Object getTrack() {
+ return xsdTrack;
+ }
+
+ public void setTrack(Object track) {
+ if (track != null && track instanceof TrackType)
+ this.xsdTrack = (TrackType) track;
+ }
+
+ @Override
+ public List<String> getLocations() {
+ return xsdTrack.getLocation();
+ }
+
+ @Override
+ public void addLocation(String location) {
+ if (location != null) {
+ xsdTrack.getLocation().add(
+ location
+ );
+ }
+ }
+
+ @Override
+ public List<String> getIdentifiers() {
+ return xsdTrack.getIdentifier();
+ }
+
+ @Override
+ public void addIdentifier(String identifier) {
+ if (identifier != null) {
+ xsdTrack.getIdentifier().add(
+ identifier
+ );
+ }
+ }
+
+ @Override
+ public String getTitle() {
+ return xsdTrack.getTitle();
+ }
+
+ @Override
+ public void setTitle(String title) {
+ xsdTrack.setTitle(title);
+ }
+
+ @Override
+ public String getCreator() {
+ return xsdTrack.getCreator();
+ }
+
+ @Override
+ public void setCreator(String creator) {
+ xsdTrack.setCreator(creator);
+ }
+
+ @Override
+ public String getAnnotation() {
+ return xsdTrack.getAnnotation();
+ }
+
+ @Override
+ public void setAnnotation(String annotation) {
+ xsdTrack.setAnnotation(annotation);
+ }
+
+ @Override
+ public String getInfo() {
+ return xsdTrack.getInfo();
+ }
+
+ @Override
+ public void setInfo(String info) {
+ xsdTrack.setInfo(info);
+ }
+
+ @Override
+ public String getImage() {
+ return xsdTrack.getImage();
+ }
+
+ @Override
+ public void setImage(String image) {
+ xsdTrack.setImage(image);
+ }
+
+ @Override
+ public String getAlbum() {
+ return xsdTrack.getAlbum();
+ }
+
+ @Override
+ public void setAlbum(String album) {
+ xsdTrack.setAlbum(album);
+ }
+
+ @Override
+ public Integer getTrackNum() {
+ BigInteger trackNum = xsdTrack.getTrackNum();
+ return trackNum != null ? trackNum.intValue() : null;
+ }
+
+ @Override
+ public void setTrackNum(Integer trackNum) {
+ xsdTrack.setTrackNum(
+ trackNum != null ? BigInteger.valueOf(trackNum) : null
+ );
+ }
+
+ @Override
+ public Integer getDuration() {
+ BigInteger duration = xsdTrack.getDuration();
+ return duration != null ? duration.intValue() : null;
+ }
+
+ @Override
+ public void setDuration(Integer duration) {
+ xsdTrack.setDuration(
+ duration != null ? BigInteger.valueOf(duration) : null
+ );
+ }
+
+ @Override
+ public List<Link> getLinks() {
+ List<Link> links = new ArrayList<>();
+ for (LinkType link : xsdTrack.getLink()) {
+ links.add(
+ PlaylistFactory.createLink(link.getRel(), link.getValue())
+ );
+ }
+ return links;
+ }
+
+ @Override
+ public void addLink(Link link) {
+ if (link != null) {
+ LinkType linkType = XSD_FACTORY.createLinkType();
+ linkType.setRel(link.getRel());
+ linkType.setValue(link.getContent());
+ xsdTrack.getLink().add(
+ linkType
+ );
+ }
+ }
+
+ @Override
+ public List<Meta> getMetas() {
+ List<Meta> metas = new ArrayList<>();
+ for (MetaType meta : xsdTrack.getMeta()) {
+ metas.add(
+ PlaylistFactory.createMeta(meta.getRel(), meta.getValue())
+ );
+ }
+ return metas;
+ }
+
+ @Override
+ public void addMeta(Meta meta) {
+ if (meta != null) {
+ MetaType metaType = XSD_FACTORY.createMetaType();
+ metaType.setRel(meta.getRel());
+ metaType.setValue(meta.getContent());
+ xsdTrack.getMeta().add(
+ metaType
+ );
+ }
+ }
+
+ @Override
+ public List<Extension> getExtensions() {
+ List<Extension> extensions = new ArrayList<>();
+ for (ExtensionType extension : xsdTrack.getExtension()) {
+ extensions.add(
+ PlaylistFactory.createExtension(
+ extension.getApplication(), extension.getContent()
+ )
+ );
+ }
+ return extensions;
+ }
+
+ @Override
+ public void addExtension(Extension extension) {
+ if (extension != null) {
+ ExtensionType extensionType = XSD_FACTORY.createExtensionType();
+ extensionType.setApplication(extension.getApplication());
+ extensionType.getContent().addAll(extension.getContent());
+ xsdTrack.getExtension().add(
+ extensionType
+ );
+ }
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf.validate;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class EmptyValidator implements Validator {
+
+ private EmptyValidator() {
+ }
+
+ public static Validator getInstance() {
+ return new EmptyValidator();
+ }
+
+ @Override
+ public void validate(Object validateObj) {
+
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf.validate;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class URIValidator implements Validator {
+
+ private URIValidator() {
+ }
+
+ public static Validator getInstance() {
+ return new URIValidator();
+ }
+
+ @Override
+ public void validate(Object validateObj) {
+
+ }
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf.validate;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import static java.lang.annotation.ElementType.FIELD;
+import static java.lang.annotation.ElementType.METHOD;
+import static java.lang.annotation.ElementType.TYPE;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@Target({TYPE, FIELD, METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Validate {
+
+ ValidatorType validatorType();
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf.validate;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public class ValidateException extends Exception {
+
+ private int code;
+
+ public ValidateException(int code, String message) {
+ super(message);
+ this.code = code;
+ }
+
+ public int getCode() {
+ return code;
+ }
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf.validate;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public interface Validator {
+
+ void validate(Object validateObj);
+
+}
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf.validate;
+
+/**
+ *
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+public enum ValidatorType {
+
+ EMPTY ( EmptyValidator.getInstance() ),
+ URI ( URIValidator.getInstance() );
+
+ private Validator validator;
+
+ private ValidatorType(Validator validator) {
+ this.validator = validator;
+ }
+
+ public Validator getValidator() {
+ return validator;
+ }
+
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- ==================================================================
+ Relax NG Schema for XSPF Version 1
+
+ $Id$
+
+ This schema was written as a service for developers who want
+ to validate the playlists generated by their applications.
+ Nobody claims it is perfect, so if you find bugs please report
+ them. In any case, the spec overrides this schema.
+
+ Further information about XSPF is available at http://www.xml.org
+
+
+ Copyright (c) 2005 Matthias Friedrich <matt@mafr.de>
+ Copyright (c) 2007-2008 Sebastian Pipping <webmaster@hartwork.org>
+
+ The schema is released under the Creative Commons
+ Attribution-ShareAlike 2.5 license.
+
+ http://creativecommons.org/licenses/by-sa/2.5/
+
+
+ ChangeLog:
+ * 2008-09-03: Allow xml:base attribute everywhere
+ Extract common elements
+ Sebastian Pipping <webmaster@hartwork.org>
+
+ * 2008-07-26: Support for xml:base attribute
+ Sebastian Pipping <webmaster@hartwork.org>
+
+ * 2007-02-16: Trang-friendly transformation of def_anything
+ Sebastian Pipping <webmaster@hartwork.org>
+
+ * 2007-02-16: Interleave wrap for track and playlist
+ to allow arbitrary element order
+ Sebastian Pipping <webmaster@hartwork.org>
+
+ * 2007-01-07: The info element's content has been changed from
+ type "text" to "anyURI", as per spec.
+ Matthias Friedrich <matt@mafr.de>
+
+ * 2006-09-25: Fixed an error: the "attribution" element now allows
+ "identifier" child element elements, too.
+ Matthias Friedrich <matt@mafr.de>
+ ================================================================== -->
+
+
+<grammar xmlns="http://relaxng.org/ns/structure/1.0"
+ datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"
+ ns="http://xspf.org/ns/0/">
+
+
+ <start>
+ <ref name="def_playlist-element"/>
+ </start>
+
+
+ <define name="xml_base-attribute">
+ <optional>
+ <attribute name="xml:base">
+ <data type="anyURI"/>
+ </attribute>
+ </optional>
+ </define>
+
+
+ <define name="def_title-element">
+ <element name="title">
+ <ref name="xml_base-attribute"/>
+ <text/>
+ </element>
+ </define>
+
+
+ <define name="def_creator-element">
+ <element name="creator">
+ <ref name="xml_base-attribute"/>
+ <text/>
+ </element>
+ </define>
+
+
+ <define name="def_annotation-element">
+ <element name="annotation">
+ <ref name="xml_base-attribute"/>
+ <text/>
+ </element>
+ </define>
+
+
+ <define name="def_info-element">
+ <element name="info">
+ <ref name="xml_base-attribute"/>
+ <data type="anyURI"/>
+ </element>
+ </define>
+
+
+ <define name="def_location-element">
+ <element name="location">
+ <ref name="xml_base-attribute"/>
+ <data type="anyURI"/>
+ </element>
+ </define>
+
+
+ <define name="def_identifier-element">
+ <element name="identifier">
+ <ref name="xml_base-attribute"/>
+ <data type="anyURI"/>
+ </element>
+ </define>
+
+
+ <define name="def_image-element">
+ <element name="image">
+ <ref name="xml_base-attribute"/>
+ <data type="anyURI"/>
+ </element>
+ </define>
+
+
+ <define name="def_link-element">
+ <element name="link">
+ <attribute name="rel">
+ <data type="anyURI"/>
+ </attribute>
+ <ref name="xml_base-attribute"/>
+
+ <data type="anyURI"/>
+ </element>
+ </define>
+
+
+ <define name="def_meta-element">
+ <element name="meta">
+ <attribute name="rel">
+ <data type="anyURI"/>
+ </attribute>
+ <ref name="xml_base-attribute"/>
+
+ <text />
+ </element>
+ </define>
+
+
+ <define name="def_extension-element">
+ <element name="extension">
+ <attribute name="application">
+ <data type="anyURI"/>
+ </attribute>
+ <ref name="xml_base-attribute"/>
+
+ <zeroOrMore>
+ <choice>
+ <element>
+ <anyName/>
+ <ref name="def_anything"/>
+ </element>
+ <text/>
+ </choice>
+ </zeroOrMore>
+ </element>
+ </define>
+
+
+ <define name="def_playlist-element">
+ <element name="playlist">
+ <attribute name="version">
+ <data type="string">
+ <param name="pattern">1</param>
+ </data>
+ </attribute>
+ <ref name="xml_base-attribute"/>
+
+ <interleave>
+ <optional>
+ <ref name="def_title-element"/>
+ </optional>
+ <optional>
+ <ref name="def_creator-element"/>
+ </optional>
+ <optional>
+ <ref name="def_annotation-element"/>
+ </optional>
+ <optional>
+ <ref name="def_info-element"/>
+ </optional>
+ <optional>
+ <ref name="def_location-element"/>
+ </optional>
+ <optional>
+ <ref name="def_identifier-element"/>
+ </optional>
+ <optional>
+ <ref name="def_image-element"/>
+ </optional>
+ <optional>
+ <element name="date">
+ <ref name="xml_base-attribute"/>
+ <data type="dateTime"/>
+ </element>
+ </optional>
+ <optional>
+ <element name="license">
+ <ref name="xml_base-attribute"/>
+ <data type="anyURI"/>
+ </element>
+ </optional>
+
+ <optional>
+ <ref name="def_attribution-element"/>
+ </optional>
+
+ <zeroOrMore>
+ <ref name="def_link-element"/>
+ </zeroOrMore>
+ <zeroOrMore>
+ <ref name="def_meta-element"/>
+ </zeroOrMore>
+ <zeroOrMore>
+ <ref name="def_extension-element"/>
+ </zeroOrMore>
+
+ <element name="trackList">
+ <ref name="xml_base-attribute"/>
+ <zeroOrMore>
+ <ref name="def_track-element"/>
+ </zeroOrMore>
+ </element>
+ </interleave>
+ </element>
+ </define>
+
+
+ <define name="def_attribution-element">
+ <element name="attribution">
+ <ref name="xml_base-attribute"/>
+
+ <zeroOrMore>
+ <choice>
+ <ref name="def_identifier-element"/>
+ <ref name="def_location-element"/>
+ </choice>
+ </zeroOrMore>
+ </element>
+ </define>
+
+
+ <define name="def_anything">
+ <interleave>
+ <zeroOrMore>
+ <element>
+ <anyName/>
+ <ref name="def_anything"/>
+ </element>
+ </zeroOrMore>
+
+ <zeroOrMore>
+ <attribute>
+ <anyName/>
+ </attribute>
+ </zeroOrMore>
+
+ <zeroOrMore>
+ <text/>
+ </zeroOrMore>
+ </interleave>
+ </define>
+
+
+ <define name="def_track-element">
+ <element name="track">
+ <ref name="xml_base-attribute"/>
+
+ <interleave>
+ <zeroOrMore>
+ <ref name="def_location-element"/>
+ </zeroOrMore>
+ <zeroOrMore>
+ <ref name="def_identifier-element"/>
+ </zeroOrMore>
+
+ <optional>
+ <ref name="def_title-element"/>
+ </optional>
+ <optional>
+ <ref name="def_creator-element"/>
+ </optional>
+ <optional>
+ <ref name="def_annotation-element"/>
+ </optional>
+ <optional>
+ <ref name="def_info-element"/>
+ </optional>
+ <optional>
+ <ref name="def_image-element"/>
+ </optional>
+ <optional>
+ <element name="album">
+ <ref name="xml_base-attribute"/>
+ <text/>
+ </element>
+ </optional>
+ <optional>
+ <element name="trackNum">
+ <ref name="xml_base-attribute"/>
+ <data type="nonNegativeInteger"/>
+ </element>
+ </optional>
+ <optional>
+ <element name="duration">
+ <ref name="xml_base-attribute"/>
+ <data type="nonNegativeInteger"/>
+ </element>
+ </optional>
+
+ <zeroOrMore>
+ <ref name="def_link-element"/>
+ </zeroOrMore>
+ <zeroOrMore>
+ <ref name="def_meta-element"/>
+ </zeroOrMore>
+ <zeroOrMore>
+ <ref name="def_extension-element"/>
+ </zeroOrMore>
+ </interleave>
+ </element>
+ </define>
+
+</grammar>
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!-- ==================================================================
+ XML Schema for XSPF Version 1
+
+ $Id$
+
+ This schema was written as a service for developers who want
+ to validate the playlists generated by their applications.
+ Nobody claims it is perfect, so if you find bugs please report
+ them. In any case, the spec overrides this schema.
+
+ Further information about XSPF is available at http://www.xml.org
+
+
+ Copyright (c) 2005 Matthias Friedrich <matt@mafr.de>
+
+ The schema is released under the Creative Commons
+ Attribution-ShareAlike 2.0 license.
+
+ http://creativecommons.org/licenses/by-sa/2.0/
+
+
+ ChangeLog:
+ * 2005-10-12: Fixed an error: the "extension" element now
+ has an "application" attribute, like in the spec.
+ * 2006-09-25: Fixed an error: the "attribution" element now allows
+ "identifier" child element elements, too.
+ ================================================================== -->
+
+<xsd:schema xmlns:xsd = "http://www.w3.org/2001/XMLSchema"
+ xmlns:xspf = "http://xspf.org/ns/0/"
+ targetNamespace="http://xspf.org/ns/0/"
+ elementFormDefault="qualified"
+ attributeFormDefault="unqualified">
+
+<xsd:element name="playlist" type="xspf:PlaylistType"/>
+
+<xsd:complexType name="PlaylistType">
+ <xsd:sequence>
+ <xsd:element name="title" type="xsd:string" minOccurs="0" maxOccurs="1"/>
+ <xsd:element name="creator" type="xsd:string" minOccurs="0" maxOccurs="1"/>
+ <xsd:element name="annotation" type="xsd:string" minOccurs="0" maxOccurs="1"/>
+ <xsd:element name="info" type="xsd:anyURI" minOccurs="0" maxOccurs="1"/>
+ <xsd:element name="location" type="xsd:anyURI" minOccurs="0" maxOccurs="1"/>
+ <xsd:element name="identifier" type="xsd:anyURI" minOccurs="0" maxOccurs="1"/>
+ <xsd:element name="image" type="xsd:anyURI" minOccurs="0" maxOccurs="1"/>
+ <xsd:element name="date" type="xsd:dateTime" minOccurs="0" maxOccurs="1"/>
+ <xsd:element name="license" type="xsd:anyURI" minOccurs="0" maxOccurs="1"/>
+ <xsd:element name="attribution" type="xspf:AttributionType" minOccurs="0" maxOccurs="1"/>
+
+ <xsd:element name="link" type="xspf:LinkType" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element name="meta" type="xspf:MetaType" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element name="extension" type="xspf:ExtensionType" minOccurs="0" maxOccurs="unbounded"/>
+
+ <xsd:element name="trackList" type="xspf:TrackListType" minOccurs="1" maxOccurs="1"/>
+ </xsd:sequence>
+ <xsd:attribute name="version" type="xspf:VersionType" use="required"/>
+</xsd:complexType>
+
+<xsd:simpleType name="VersionType">
+ <xsd:restriction base="xsd:string">
+ <xsd:pattern value="1"/>
+ </xsd:restriction>
+</xsd:simpleType>
+
+<xsd:complexType name="AttributionType">
+ <xsd:choice minOccurs="0" maxOccurs="unbounded">
+ <xsd:element name="identifier" type="xsd:anyURI"/>
+ <xsd:element name="location" type="xsd:anyURI"/>
+ </xsd:choice>
+</xsd:complexType>
+
+<xsd:complexType name="LinkType">
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:anyURI">
+ <xsd:attribute name="rel" type="xsd:anyURI" use="required"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+</xsd:complexType>
+
+<xsd:complexType name="MetaType">
+ <xsd:simpleContent>
+ <xsd:extension base="xsd:string">
+ <xsd:attribute name="rel" type="xsd:anyURI" use="required"/>
+ </xsd:extension>
+ </xsd:simpleContent>
+</xsd:complexType>
+
+<xsd:complexType name="ExtensionType">
+ <xsd:complexContent mixed="true">
+ <xsd:restriction base="xsd:anyType">
+ <xsd:sequence>
+ <xsd:any processContents="skip" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+ <xsd:attribute name="application" type="xsd:anyURI" use="required"/>
+ </xsd:restriction>
+ </xsd:complexContent>
+</xsd:complexType>
+
+<xsd:complexType name="TrackListType">
+ <xsd:sequence>
+ <xsd:element name="track" type="xspf:TrackType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+</xsd:complexType>
+
+<xsd:complexType name="TrackType">
+ <xsd:sequence>
+ <xsd:element name="location" type="xsd:anyURI" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element name="identifier" type="xsd:anyURI" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element name="title" type="xsd:string" minOccurs="0" maxOccurs="1"/>
+ <xsd:element name="creator" type="xsd:string" minOccurs="0" maxOccurs="1"/>
+ <xsd:element name="annotation" type="xsd:string" minOccurs="0" maxOccurs="1"/>
+ <xsd:element name="info" type="xsd:anyURI" minOccurs="0" maxOccurs="1"/>
+ <xsd:element name="image" type="xsd:anyURI" minOccurs="0" maxOccurs="1"/>
+ <xsd:element name="album" type="xsd:string" minOccurs="0" maxOccurs="1"/>
+ <xsd:element name="trackNum" type="xsd:nonNegativeInteger" minOccurs="0" maxOccurs="1"/>
+ <xsd:element name="duration" type="xsd:nonNegativeInteger" minOccurs="0" maxOccurs="1"/>
+
+ <xsd:element name="link" type="xspf:LinkType" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element name="meta" type="xspf:MetaType" minOccurs="0" maxOccurs="unbounded"/>
+ <xsd:element name="extension" type="xspf:ExtensionType" minOccurs="0" maxOccurs="unbounded"/>
+ </xsd:sequence>
+</xsd:complexType>
+
+</xsd:schema>
--- /dev/null
+/*
+ * Copyright (c) 2015. Developed by Hedgecode.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.hedgecode.xml.xspf;
+
+import java.io.File;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for {@link XSPF}.
+ *
+ * @author Dmitry Samoshin aka gotty
+ */
+@RunWith(JUnit4.class)
+public class XSPFTest extends Assert {
+
+ private static final String XSPF_FILE_DIR = "/";
+ private static final String XSPF_PLAYLIST_FILE = "playlist.xspf";
+ private static final String XSPF_TORRENT_FILE = "torrent-tv.ru.xspf";
+
+ @Test
+ public void testBind() throws Exception {
+
+ File xspfFile = new File(
+ XSPFTest.class.getResource(
+ XSPF_FILE_DIR + XSPF_PLAYLIST_FILE
+ ).toURI()
+ );
+
+
+ Playlist playlist = XSPF.create(xspfFile);
+
+ playlist.write(
+ new File("test.xspf")
+ );
+ }
+
+ @Test
+ public void testCreate() throws Exception {
+
+ Playlist playlist = XSPF.create(XSPFConstants.Format.XSD);
+ playlist.setTitle("Title");
+ playlist.setLocation("Location");
+ XSPF.addTrack(playlist, "a.mp3", "First MP3");
+ XSPF.addTrack(playlist, "b.mp3", "Second MP3");
+ XSPF.addTrack(playlist, "c.mp3", "Third MP3");
+ playlist.write(
+ new File("test2.xspf")
+ );
+ }
+
+}
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?>
+<playlist version="1" xmlns="http://xspf.org/ns/0/">
+ <title>My playlist</title>
+ <creator>Jane Doe</creator>
+ <annotation>My favorite songs</annotation>
+ <info>http://example.com/myplaylists</info>
+ <location>http://example.com/myplaylists/myplaylist</location>
+ <identifier>magnet:?xt=urn:sha1:YNCKHTQCWBTRNJIV4WNAE52SJUQCZO5C</identifier>
+ <image>http://example.com/img/mypicture</image>
+ <date>2005-01-08T17:10:47-05:00</date>
+ <license>http://creativecommons.org/licenses/by/1.0/</license>
+ <attribution>
+ <identifier>http://bar.com/secondderived.xspf</identifier>
+ <location>http://foo.com/original.xspf</location>
+ </attribution>
+ <link rel="http://foaf.example.org/namespace/version1">http://socialnetwork.example.org/foaf/mary.rdfs</link>
+ <meta rel="http://example.org/key">value</meta>
+ <extension application="http://example.com">
+ <clip start="25000" end="34500"/>
+ </extension>
+ <trackList>
+ <track>
+ <location>http://example.com/my.mp3</location>
+ <identifier>magnet:?xt=urn:sha1:YNCKHTQCWBTRNJIV4WNAE52SJUQCZO5C</identifier>
+ <title>My Way</title>
+ <creator>Frank Sinatra</creator>
+ <annotation>This is my theme song.</annotation>
+ <info>http://franksinatra.com/myway</info>
+ <image>http://franksinatra.com/img/myway</image>
+ <album>Frank Sinatra's Greatest Hits</album>
+ <trackNum>3</trackNum>
+ <duration>19200</duration>
+ <link rel="http://foaf.org/namespace/version1">http://socialnetwork.org/foaf/mary.rdfs</link>
+ <meta rel="http://example.org/key">value</meta>
+ <extension application="http://example.com">
+ <clip start="25000" end="34500"/>
+ </extension>
+ </track>
+ </trackList>
+</playlist>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="UTF-8"?><playlist xmlns="http://xspf.org/ns/0/" version=""><annotation>Избранные каналы TORRENT-TV.RU</annotation><trackList xmlns="http://xspf.org/ns/0/"><track xmlns="http://xspf.org/ns/0/"><location>http://content.torrent-tv.ru/djY5Y2h1MFcrS0FWQUR0dlp1SGp2ZTJudmNlTCs1ajJLVHpDbFhIS3hLWGtId0d0ako2c0RiaFd0K1d5TkpKLzgrWFdLbzVBZVI3ZXo1aEpKNVNOUkE9PQ/cdn/5_reg.acelive</location><title>Eurosport</title></track><track xmlns="http://xspf.org/ns/0/"><location>http://content.torrent-tv.ru/ZWcrTkgwY3FXZURPVkdjZkEvU1ErVXFqeWFXRE1Ed1Rzd045TUxnR1JRTG9GbEY1dGwxa013OWRDQ1ovUnFTQlNvSGMxcWtVQlh4OWkrOVZ6QVA4MGc9PQ/cdn/6_reg.acelive</location><title>Eurospоrt 2</title></track><track xmlns="http://xspf.org/ns/0/"><location>http://content.torrent-tv.ru/Q1lWeUt0VnJXYnU1WFliNWhKd2xwWE91MUJsSGRCQVV6YzNyK3VFWTJRajhJUVVpTDY3RjR2eDNxV1ZCbUpDb0w1aUFjcXg1UC85YWt6clZhZTRKd1E9PQ/13250.acelive</location><title>Eurospоrt 2 North-East</title></track><track xmlns="http://xspf.org/ns/0/"><location>http://content.torrent-tv.ru/VVhaVmNyL05vb0pBUS9tUGFTWDh1ZE45Q25yTUpWWVFORlhTYUx2T2lPL2ozUFNISzR5MXkrVXBFZ1VJblMzckVScHpZTXYxWktudGVwSWwwYzgrZmc9PQ/cdn/38_reg.acelive</location><title>НТВ+ Спорт</title></track><track xmlns="http://xspf.org/ns/0/"><location>http://content.torrent-tv.ru/U0NYRG16NTR3a0lKWlNkOEdtT3RoT1czVVk4YjdRanpKbmtMbit0UTJuSnhhdzFnOXhqejZxK0QyYy9mSjdzVEdweEpVWnExd3ZPc3gxOVZpZmE2cXc9PQ/cdn/222_reg.acelive</location><title>НТВ+ Спорт плюс</title></track><track xmlns="http://xspf.org/ns/0/"><location>http://content.torrent-tv.ru/K2ZVWDZEeW9GR3FrZHppeCsrQTJZeU9PUGROa2dDeTRxdU5VeDRwY3JMVlFhRk0vaXAxTG50Z28yZmxLV0JHR2xrTG1XM3pjMm5INUJPQ0xEZ0tlN3c9PQ/cdn/172_reg.acelive</location><title>Eurosport HD</title></track><track xmlns="http://xspf.org/ns/0/"><location>http://content.torrent-tv.ru/eUh5WHVlbEcyenUyTVJOeGFMNWNZeGlUdHlBU1hwWTJRY2JzTEdXZU81WGR0ME96dUltQ2w5UFNzWElyRnNSZEFJU3FROHA0UDM3My96a3h0SHJhUnc9PQ/11160.acelive</location><title>Eurospоrt 2 North-East HD</title></track><track xmlns="http://xspf.org/ns/0/"><location>http://content.torrent-tv.ru/VElRQ2tIRHdyelk4RDloOTlWaXlsZDd5RTlZd1Jlck1DVkVMcVo1RmpTamFROFNQcFVZOW0yU0hDenh6T0EyUVAxdUtsUlliMlpRVmlHSVRuYUUxQ1E9PQ/cdn/625_reg.acelive</location><title>НТВ+ Футбол 1 HD</title></track><track xmlns="http://xspf.org/ns/0/"><location>http://content.torrent-tv.ru/MHdOeXdMQlNPVSt1TDIrcFlyWnFmOTJxbWJ5QlR0YmVsd2JkdlppK1dwbmVDYnE5VzlIWGlOZklHYlR3eHpYUHlmZTNwN3poY05vaTN1bWJqQnNxSFE9PQ/cdn/611_reg.acelive</location><title>НТВ+ Футбол 2 HD</title></track><track xmlns="http://xspf.org/ns/0/"><location>http://content.torrent-tv.ru/N1NVQ1dWdmlkelpqQVlyYVNCbkFoQ2dBM0FoWlpQaHRmdzRpTlRVN1lDbm5ZU2EzTEVPc0tNOU9ONWV6Q0k2TUdyd3dGaHc3OU0zWlVLdFk1RkRQUXc9PQ/cdn/646_reg.acelive</location><title>НТВ+ Футбол 3 HD</title></track><track xmlns="http://xspf.org/ns/0/"><location>http://content.torrent-tv.ru/RzNvVStPUTFNUGFyZGFtRkR5N1dLUExwdzR6NGs0Q0ZIYmNqcVdydVByTnlSTlRVSDcxWGMrTjZNNmxocUJleXozRmxlUkd2YkNqZXpLcS95b0QvdWc9PQ/cdn/473_reg.acelive</location><title>Спорт</title></track><track xmlns="http://xspf.org/ns/0/"><location>http://content.torrent-tv.ru/Rm9ZbWZGN1lFbnJtRGtnem5ScSsrQjA4M1FudTh3dlBkcmxKK2dHMXFaUVhZMHYwd29LMFA4aHhqTHBKbkJtaUxWUS9jNCtnMzR1WXhaakZ1SmdHalE9PQ/cdn/526_reg.acelive</location><title>Спорт 1 HD</title></track><track xmlns="http://xspf.org/ns/0/"><location>http://content.torrent-tv.ru/NUhOTlZXa3QxSnI1SzVUdFR2K2VQV3JGWTZVMTN0SHNsTFVKcHZERVFOU29zTDh3bWV0bHZDc2lWU0NqQURqTVpPazlzNlB0RGg0dHhjN0l0T0RXdHc9PQ/cdn/112_reg.acelive</location><title>HD Спорт</title></track><track xmlns="http://xspf.org/ns/0/"><location>http://content.torrent-tv.ru/QjVVeFlzWStIWnZrYUpVTkl1eCt1ZXVtWXJIMEhXOUxBYWc5cGYzMUFYWVlRQ3FlV2gxK0dOcmx1OHlCUmtneGQ5dlBiMHJVQ3Q1RFRsZ1AwQ2Mzc3c9PQ/cdn/538_reg.acelive</location><title>КХЛ HD</title></track><track xmlns="http://xspf.org/ns/0/"><location>http://content.torrent-tv.ru/dUlQSjB4L0NZMTN1YjlUcHJQS0VpZ0YyMmtodUI3bVZGTWJiR2xuS3RPZDhyWGF4M2tzbGhvaFhHbmQzWU1Fb1VOeENmbThRUGVDMDNBMVVTU2Izcmc9PQ/cdn/487_all.acelive</location><title>Paramount Comedy</title></track><track xmlns="http://xspf.org/ns/0/"><location>http://content.torrent-tv.ru/eDEwazVwZWFXS0tPZXNPeVc0THljdFM5aTZNTlRRSmYwQ3pPcW1iWkY2djZsb2g1RE9PT0YrNzNLNXFVd0RnUitkWnNHcGIvTUMrbWhIUGY1NFVGSlE9PQ/11181.acelive</location><title>Paramount Comedy HD</title></track><track xmlns="http://xspf.org/ns/0/"><location>http://content.torrent-tv.ru/U0NrTzNaMFZ1U1F6ODMwbVppQXFEdXNzUkVNM1UrV24wR3FVMmdISzRoM3NLNHdoMFhSajh5aEFVQkNtYzgvSkZHdFhlZ0NtOXBFUG91UG9lVmxjZWc9PQ/cdn/28_reg.acelive</location><title>Перец</title></track><track xmlns="http://xspf.org/ns/0/"><location>http://content.torrent-tv.ru/cWpKZHZjbHRiZnRleGx4YzhudjI2N3lNSVMwREVCS2VralBHbk9mMTZZK3JHM05HU3gzOGtJSzlZMUJ3dy84Yng0ZEI4M2Z1MGRjRHo1YlpJTXdrdEE9PQ/cdn/731_reg.acelive</location><title>Мульт</title></track><track xmlns="http://xspf.org/ns/0/"><location>http://content.torrent-tv.ru/ZlJ5ZXBkOEd0SG56R1JFdzdyWC8zT2RSNlV0aEN1M1FUTHB4RzVyekJQajMvNXZ3R3Bsc3BkbGQwQytHb3pJdzZhR3FoeEFyVW81OG1kS1kzQXdzN0E9PQ/cdn/69_reg.acelive</location><title>TV 1000</title></track><track xmlns="http://xspf.org/ns/0/"><location>http://content.torrent-tv.ru/V3ppeE12NkFBbE5rNkk0blM3V2ZrMjc3b09jVWFoMjYzb3BLSTJQS3ZwN2c4M2Vxc0drVTlRQjdrRXlCaTAvdzNBKzNHbHUxOGJydTFLOWRXSFkzTUE9PQ/cdn/118_reg.acelive</location><title>TV 1000 Русское кино</title></track><track xmlns="http://xspf.org/ns/0/"><location>http://content.torrent-tv.ru/dGJobWkvQXpseTk2ZFUwSXFXWkJIT2c4dDlpSGpSZUdhcHFiWTk2Qm0zRVZJbG9jVmdzamdCTjVWVm9wS0dIbFVvNlhzblJ1NXA5djROditncVUrdFE9PQ/cdn/557_reg.acelive</location><title>TV1000 Comedy HD</title></track><track xmlns="http://xspf.org/ns/0/"><location>http://content.torrent-tv.ru/Zkx6VUJPSE04OVJyNEhqOU9pVGx4ZmRFMHRhZWtud1c2S2psRmt4VlJvZlBjczRtU0J2N0RxU0ZCRlFmcWNtVVpQeUpQQzAwT3hLdTFuS0lJSGU3cWc9PQ/cdn/36_reg.acelive</location><title>НТВ+ Наше кино</title></track><track xmlns="http://xspf.org/ns/0/"><location>http://content.torrent-tv.ru/aTBnUEUzbXlNa1BpK0xwSDFPcnNsYmhlbDV0aW9INGpDTG9nZ0Z4ckFXcko1VEJwbVZhVitVQjRBcjVGZlE3UGw1eGtpMUJ1TVZ3SjNXV2t2NlV3ZWc9PQ/cdn/228_reg.acelive</location><title>НТВ+ Кино плюс</title></track><track xmlns="http://xspf.org/ns/0/"><location>http://content.torrent-tv.ru/TzJrNXFUdC9DRUR4bDRaSjVPakE4bDZkbm4xWlJnYmVRWVZYRFZId2hFRnRzUk9vNkxNNmpDUDF3N0hjdk1xYWxWaWwwVUd3RmMvUm83QTNYQi9vcVE9PQ/cdn/77_reg.acelive</location><title>НТВ+ Кинохит</title></track><track xmlns="http://xspf.org/ns/0/"><location>http://content.torrent-tv.ru/bE5GNkFqajdjS2NYRDU4VTNLd3FtWmNIbnJpNzFNTE9kTko4T3RwR0I2NC9Xbm9ZNUw0Qmptd0xEVUM5V3JGWTk0bFJTOURmemMzQ0lrVUNQSnNHSWc9PQ/cdn/37_reg.acelive</location><title>НТВ+ Премьера</title></track><track xmlns="http://xspf.org/ns/0/"><location>http://content.torrent-tv.ru/QnNHQndPYWU2TGNWUnVCOThOMDZxeUVwY0JJYkV5OG1YVDNRYnBLZXZXRUFNODU4OHRDSFFrQzJreGRWZ1lDNWpKS2RNZEJFOWd0Q1dNOFFzclZ0VHc9PQ/cdn/81_reg.acelive</location><title>НТВ+ Наше новое кино</title></track><track xmlns="http://xspf.org/ns/0/"><location>http://content.torrent-tv.ru/cXRrYUFOendTTWpNaCtDNG45MTFMYXIzZ0tJK094Ly9YOEFSb3p2WmhlTlM3dUhndWcrYjJqWG16Y1B3bm9TWnhGK3p4blNBd3FqU0dEZStnZDR3NkE9PQ/cdn/35_reg.acelive</location><title>НТВ+ Киноклуб</title></track><track xmlns="http://xspf.org/ns/0/"><location>http://content.torrent-tv.ru/SkVDVDV4dTl1YWUxYitJdHJwTmplL2VkdWRuN282V1RQbmd5ek9QYVdSMGxoR0FvS2JpcE1XMFRKY2twb0JZU240cVd5RnYrclRHUVlKUnNYQ1Iwdnc9PQ/cdn/82_reg.acelive</location><title>НТВ+ Кино Союз</title></track><track xmlns="http://xspf.org/ns/0/"><location>http://content.torrent-tv.ru/SUxaNmU2aVhBbDMrUEkxK25HQ1VITkVYcEdySnJZUzBTMEEzZXdlL0VnWVJtYm1ib3FWSmZPR3lkUHBIZ0RFWUxXSStzRTMyQThvVENqeDV3VWQ2UkE9PQ/cdn/691_reg.acelive</location><title>НТВ+ 3D</title></track></trackList></playlist>
\ No newline at end of file