Coverage Report - org.jaudiotagger.audio.generic.AbstractTag
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractTag
78%
69/88
60%
23/38
2
AbstractTag$1
86%
13/15
100%
12/12
2
 
 1  
 /*
 2  
  * jaudiotagger library
 3  
  *
 4  
  * This library is free software; you can redistribute it and/or
 5  
  * modify it under the terms of the GNU Lesser General Public
 6  
  * License as published by the Free Software Foundation; either
 7  
  * version 2.1 of the License, or (at your option) any later version.
 8  
  *  
 9  
  * This library is distributed in the hope that it will be useful,
 10  
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11  
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 12  
  * Lesser General Public License for more details.
 13  
  * 
 14  
  * You should have received a copy of the GNU Lesser General Public
 15  
  * License along with this library; if not, write to the Free Software
 16  
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 17  
  */
 18  
 package org.jaudiotagger.audio.generic;
 19  
 
 20  
 import org.jaudiotagger.tag.*;
 21  
 import org.jaudiotagger.tag.datatype.Artwork;
 22  
 
 23  
 import java.util.*;
 24  
 
 25  
 /**
 26  
  * This class is the default implementation for
 27  
  * {@link org.jaudiotagger.tag.Tag} and introduces some more useful
 28  
  * functionality to be implemented.<br>
 29  
  *
 30  
  * @author RaphaĆ«l Slinckx
 31  
  */
 32  1218
 public abstract class AbstractTag implements Tag
 33  
 {
 34  
     /**
 35  
      * Stores the amount of {@link TagField} with {@link TagField#isCommon()}
 36  
      * <code>true</code>.
 37  
      */
 38  1218
     protected int commonNumber = 0;
 39  
 
 40  
     /**
 41  
      * This map stores the {@linkplain TagField#getId() ids} of the stored
 42  
      * fields to the {@linkplain TagField fields} themselves. Because a linked hashMap is used the order
 43  
      * that they are added in is preserved, the only exception to this rule is when two fields of the same id
 44  
      * exist, both will be returned according to when the first item was added to the file. <br>
 45  
      */
 46  1218
     protected Map<String, List<TagField>> fields = new LinkedHashMap<String, List<TagField>>();
 47  
 
 48  
     /**
 49  
      * Add field
 50  
      *
 51  
      * @see org.jaudiotagger.tag.Tag#addField(org.jaudiotagger.tag.TagField)
 52  
      *      <p/>
 53  
      *      Changed so add empty fields
 54  
      */
 55  
     public void addField(TagField field)
 56  
     {
 57  14768
         if (field == null)
 58  
         {
 59  0
             return;
 60  
         }
 61  
 
 62  14768
         List<TagField> list = fields.get(field.getId());
 63  
 
 64  
         // There was no previous item
 65  14768
         if (list == null)
 66  
         {
 67  14488
             list = new ArrayList<TagField>();
 68  14488
             list.add(field);
 69  14488
             fields.put(field.getId(), list);
 70  14488
             if (field.isCommon())
 71  
             {
 72  3278
                 commonNumber++;
 73  
             }
 74  
         }
 75  
         else
 76  
         {
 77  
             // We append to existing list
 78  280
             list.add(field);
 79  
         }
 80  14768
     }
 81  
 
 82  
 
 83  
     /**
 84  
      * Get list of fields within this tag with the specified id
 85  
      *
 86  
      * @see org.jaudiotagger.tag.Tag#get(java.lang.String)
 87  
      */
 88  
     public List<TagField> get(String id)
 89  
     {
 90  9003
         List<TagField> list = fields.get(id);
 91  
 
 92  9003
         if (list == null)
 93  
         {
 94  367
             return new ArrayList<TagField>();
 95  
         }
 96  
 
 97  8636
         return list;
 98  
     }
 99  
 
 100  
     /**
 101  
      * @param id
 102  
      * @return
 103  
      */
 104  
 
 105  
     //Needs to be overridden
 106  
     //TODO remove
 107  
     public List<TagField> getFields(FieldKey id) throws KeyNotFoundException
 108  
     {
 109  0
         List<TagField> list = fields.get(id.name());
 110  0
         if (list == null)
 111  
         {
 112  0
             return new ArrayList<TagField>();
 113  
         }
 114  0
         return list;
 115  
     }
 116  
 
 117  
 
 118  
     /**
 119  
      * @param id
 120  
      * @return matches for this audio-specific key
 121  
      */
 122  
     public String getFirst(String id)
 123  
     {
 124  6435
         List<TagField> l = get(id);
 125  6435
         return (l.size() != 0) ? l.get(0).toString() : "";
 126  
     }
 127  
 
 128  
     public TagField getFirstField(String id)
 129  
     {
 130  176
         List<TagField> l = get(id);
 131  176
         return (l.size() != 0) ? l.get(0) : null;
 132  
     }
 133  
 
 134  
 
 135  
     /**
 136  
      * @see org.jaudiotagger.tag.Tag#getFields()
 137  
      */
 138  
     public Iterator<TagField> getFields()
 139  
     {
 140  980
         final Iterator<Map.Entry<String, List<TagField>>> it = this.fields.entrySet().iterator();
 141  980
         return new Iterator<TagField>()
 142  
         {
 143  
             private Iterator<TagField> fieldsIt;
 144  
 
 145  
             private void changeIt()
 146  
             {
 147  14623
                 if (!it.hasNext())
 148  
                 {
 149  137
                     return;
 150  
                 }
 151  
 
 152  14486
                 Map.Entry<String, List<TagField>> e = it.next();
 153  14486
                 List<TagField> l = e.getValue();
 154  14486
                 fieldsIt = l.iterator();
 155  14486
             }
 156  
 
 157  
             public boolean hasNext()
 158  
             {
 159  15671
                 if (fieldsIt == null)
 160  
                 {
 161  980
                     changeIt();
 162  
                 }
 163  15671
                 return it.hasNext() || (fieldsIt != null && fieldsIt.hasNext());
 164  
             }
 165  
 
 166  
             public TagField next()
 167  
             {
 168  14691
                 if (!fieldsIt.hasNext())
 169  
                 {
 170  13643
                     changeIt();
 171  
                 }
 172  
 
 173  14691
                 return fieldsIt.next();
 174  
             }
 175  
 
 176  15671
             public void remove()
 177  
             {
 178  0
                 fieldsIt.remove();
 179  0
             }
 180  
         };
 181  
     }
 182  
 
 183  
     /**
 184  
      * Return field count
 185  
      * <p/>
 186  
      * TODO:There must be a more efficient way to do this.
 187  
      *
 188  
      * @return field count
 189  
      */
 190  
     public int getFieldCount()
 191  
     {
 192  209
         Iterator it = getFields();
 193  209
         int count = 0;
 194  1786
         while (it.hasNext())
 195  
         {
 196  1577
             count++;
 197  1577
             it.next();
 198  
         }
 199  209
         return count;
 200  
     }
 201  
 
 202  
 
 203  
     /**
 204  
      * Does this tag contain any comon fields
 205  
      *
 206  
      * @see org.jaudiotagger.tag.Tag#hasCommonFields()
 207  
      */
 208  
     public boolean hasCommonFields()
 209  
     {
 210  0
         return commonNumber != 0;
 211  
     }
 212  
 
 213  
     /**
 214  
      * Does this tag contain a field with the specified id
 215  
      *
 216  
      * @see org.jaudiotagger.tag.Tag#hasField(java.lang.String)
 217  
      */
 218  
     public boolean hasField(String id)
 219  
     {
 220  16
         return get(id).size() != 0;
 221  
     }
 222  
 
 223  
     /**
 224  
      * Determines whether the given charset encoding may be used for the
 225  
      * represented tagging system.
 226  
      *
 227  
      * @param enc charset encoding.
 228  
      * @return <code>true</code> if the given encoding can be used.
 229  
      */
 230  
     protected abstract boolean isAllowedEncoding(String enc);
 231  
 
 232  
     /**
 233  
      * Is this tag empty
 234  
      *
 235  
      * @see org.jaudiotagger.tag.Tag#isEmpty()
 236  
      */
 237  
     public boolean isEmpty()
 238  
     {
 239  282
         return fields.size() == 0;
 240  
     }
 241  
 
 242  
     /**
 243  
      * Create new field and set it in the tag
 244  
      *
 245  
      * @param genericKey
 246  
      * @param value
 247  
      * @throws KeyNotFoundException
 248  
      * @throws FieldDataInvalidException
 249  
      */
 250  
     public void setField(FieldKey genericKey, String value) throws KeyNotFoundException, FieldDataInvalidException
 251  
     {
 252  510
         TagField tagfield = createField(genericKey,value);
 253  494
         setField(tagfield);
 254  494
     }
 255  
 
 256  
     
 257  
 
 258  
      /**
 259  
      * Create new field and add it to the tag
 260  
      *
 261  
      * @param genericKey
 262  
      * @param value
 263  
      * @throws KeyNotFoundException
 264  
      * @throws FieldDataInvalidException
 265  
      */
 266  
     public void addField(FieldKey genericKey, String value) throws KeyNotFoundException, FieldDataInvalidException
 267  
     {
 268  189
         TagField tagfield = createField(genericKey,value);
 269  189
         addField(tagfield);
 270  189
     }
 271  
 
 272  
     /**
 273  
      * Set field
 274  
      * <p/>
 275  
      * Changed:Just because field is empty it doesnt mean it should be deleted. That should be the choice
 276  
      * of the developer. (Or does this break things)
 277  
      *
 278  
      * @see org.jaudiotagger.tag.Tag#setField(org.jaudiotagger.tag.TagField)
 279  
      */
 280  
     public void setField(TagField field)
 281  
     {
 282  4646
         if (field == null)
 283  
         {
 284  0
             return;
 285  
         }
 286  
 
 287  
         // If there is already an existing field with same id
 288  
         // and both are TextFields, we replace the first element
 289  4646
         List<TagField> list = fields.get(field.getId());
 290  4646
         if (list != null)
 291  
         {
 292  600
             list.set(0, field);
 293  600
             return;
 294  
         }
 295  
 
 296  
         // Else we put the new field in the fields.
 297  4046
         list = new ArrayList<TagField>();
 298  4046
         list.add(field);
 299  4046
         fields.put(field.getId(), list);
 300  4046
         if (field.isCommon())
 301  
         {
 302  1041
             commonNumber++;
 303  
         }
 304  4046
     }
 305  
 
 306  
     /**
 307  
      * Set or add encoding
 308  
      *
 309  
      * @see org.jaudiotagger.tag.Tag#setEncoding(java.lang.String)
 310  
      */
 311  
     public boolean setEncoding(String enc)
 312  
     {
 313  0
         if (!isAllowedEncoding(enc))
 314  
         {
 315  0
             return false;
 316  
         }
 317  
 
 318  0
         Iterator it = getFields();
 319  0
         while (it.hasNext())
 320  
         {
 321  0
             TagField field = (TagField) it.next();
 322  0
             if (field instanceof TagTextField)
 323  
             {
 324  0
                 ((TagTextField) field).setEncoding(enc);
 325  
             }
 326  0
         }
 327  
 
 328  0
         return true;
 329  
     }
 330  
 
 331  
     /**
 332  
      * (overridden)
 333  
      *
 334  
      * @see java.lang.Object#toString()
 335  
      */
 336  
     public String toString()
 337  
     {
 338  153
         StringBuffer out = new StringBuffer();
 339  153
         out.append("Tag content:\n");
 340  153
         Iterator it = getFields();
 341  3212
         while (it.hasNext())
 342  
         {
 343  3059
             TagField field = (TagField) it.next();
 344  3059
             out.append("\t");
 345  3059
             out.append(field.getId());
 346  3059
             out.append(":");
 347  3059
             out.append(field.toString());
 348  3059
             out.append("\n");
 349  3059
         }
 350  153
         return out.toString().substring(0, out.length() - 1);
 351  
     }
 352  
 
 353  
     /**
 354  
      *
 355  
      * @param genericKey
 356  
      * @param value
 357  
      * @return
 358  
      * @throws KeyNotFoundException
 359  
      * @throws FieldDataInvalidException
 360  
      */
 361  
     public abstract TagField createField(FieldKey genericKey, String value) throws KeyNotFoundException, FieldDataInvalidException;
 362  
 
 363  
     /**
 364  
      *
 365  
      * @param genericKey
 366  
      * @return
 367  
      * @throws KeyNotFoundException
 368  
      */
 369  
     public abstract String getFirst(FieldKey genericKey) throws KeyNotFoundException;
 370  
 
 371  
     /**
 372  
      * 
 373  
      * @param genericKey
 374  
      * @return
 375  
      * @throws KeyNotFoundException
 376  
      */
 377  
     public abstract TagField getFirstField(FieldKey genericKey) throws KeyNotFoundException;
 378  
 
 379  
     /**
 380  
      * 
 381  
      * @param fieldKey
 382  
      * @throws KeyNotFoundException
 383  
      */
 384  
     public abstract void deleteField(FieldKey fieldKey) throws KeyNotFoundException;
 385  
 
 386  
 
 387  
     /**
 388  
      * Delete all ocurrences of field.
 389  
      *
 390  
      * @param key
 391  
      */
 392  
     protected void deleteField(String key)
 393  
     {
 394  71
         Object removed = fields.remove(key);
 395  
         //if (removed != null && field.isCommon())
 396  
         //    commonNumber--;
 397  71
     }
 398  
 
 399  
     public Artwork getFirstArtwork()
 400  
     {
 401  24
         List<Artwork> artwork = getArtworkList();
 402  24
         if(artwork.size()>0)
 403  
         {
 404  24
             return artwork.get(0);
 405  
         }
 406  0
         return null;
 407  
     }
 408  
 
 409  
      /**
 410  
      * Create field and then set within tag itself
 411  
      *
 412  
      * @param artwork
 413  
      * @throws FieldDataInvalidException
 414  
      */
 415  
     public void setField(Artwork artwork) throws FieldDataInvalidException
 416  
     {
 417  20
         this.setField(createField(artwork));
 418  12
     }
 419  
 
 420  
      /**
 421  
      * Create field and then add within tag itself
 422  
      *
 423  
      * @param artwork
 424  
      * @throws FieldDataInvalidException
 425  
      */
 426  
     public void addField(Artwork artwork) throws FieldDataInvalidException
 427  
     {
 428  0
        this.addField(createField(artwork));
 429  0
     }
 430  
 
 431  
 
 432  
     /**
 433  
      * Delete all instance of artwork Field
 434  
      *
 435  
      * @throws KeyNotFoundException
 436  
      */
 437  
     public void deleteArtworkField() throws KeyNotFoundException
 438  
     {
 439  16
         this.deleteField(FieldKey.COVER_ART);
 440  8
     }
 441  
 }