--- /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());
+ }
+ }
+ }
+ }
+}