Program: 47255
Project: 47255
Buggy source:
/** 
 * Adds a new DLNAResource to the child list. Only useful if this object is of the container type. <P> TODO: (botijo) check what happens with the child object. This function can and will transform the child object. If the transcode option is set, the child item is converted to a container with the real item and the transcode option folder. There is also a parser in order to get the right name and type, I suppose. Is this the right place to be doing things like these? <p> FIXME: Ideally the logic below is completely renderer-agnostic. Focus on harvesting generic data and transform it for a specific renderer as late as possible.
 * @param child DLNAResource to add to a container type.
 */
public void addChild(DLNAResource child){
  if (child == null) {
    LOGGER.error("String_Node_Str",getName());
    LOGGER.debug("String_Node_Str",new NullPointerException("String_Node_Str"));
    return;
  }
  child.setParent(this);
  child.setMasterParent(getMasterParent());
  if (getParent() != null) {
    setDefaultRenderer(getParent().getDefaultRenderer());
  }
  if (PMS.filter(getDefaultRenderer(),child)) {
    LOGGER.debug("String_Node_Str" + child.getName() + "String_Node_Str"+ getDefaultRenderer().getRendererName());
    return;
  }
  try {
    if (child.isValid()) {
      LOGGER.trace("String_Node_Str",child.getName(),child.getClass().getName());
      if (allChildrenAreFolders && !child.isFolder()) {
        allChildrenAreFolders=false;
      }
      child.resHash=Math.abs(child.getSystemName().hashCode() + resumeHash());
      DLNAResource resumeRes=null;
      ResumeObj r=ResumeObj.create(child);
      if (r != null) {
        resumeRes=child.clone();
        resumeRes.resume=r;
        resumeRes.resHash=child.resHash;
        addChildInternal(resumeRes);
      }
      addChildInternal(child);
      boolean parserV2=child.getMedia() != null && getDefaultRenderer() != null && getDefaultRenderer().isMediaParserV2();
      if (parserV2) {
        String mimeType=getDefaultRenderer().getFormatConfiguration().match(child.getMedia());
        if (mimeType != null) {
          if (!FormatConfiguration.MIMETYPE_AUTO.equals(mimeType)) {
            LOGGER.trace("String_Node_Str",child.getMedia().getMimeType(),child.getName(),mimeType);
            child.getMedia().setMimeType(mimeType);
          }
          LOGGER.trace("String_Node_Str",child.getName(),child.getMedia().getMimeType());
        }
 else {
          LOGGER.trace("String_Node_Str",child.getName());
        }
      }
      if (child.getFormat() != null) {
        String configurationSkipExtensions=configuration.getDisableTranscodeForExtensions();
        String rendererSkipExtensions=null;
        if (getDefaultRenderer() != null) {
          rendererSkipExtensions=getDefaultRenderer().getStreamedExtensions();
        }
        boolean skip=child.getFormat().skip(configurationSkipExtensions,rendererSkipExtensions);
        setSkipTranscode(skip);
        if (skip) {
          LOGGER.trace("String_Node_Str",child.getName());
        }
        if (parserV2 || (child.getFormat().transcodable() && child.getMedia() == null)) {
          if (!parserV2) {
            child.setMedia(new DLNAMediaInfo());
          }
          Player player=null;
          String name=getName();
          if (!configuration.isHideRecentlyPlayedFolder(null)) {
            player=child.getPlayer();
          }
 else {
            for (            Player p : PlayerFactory.getPlayers()) {
              String end="String_Node_Str" + p.id() + "String_Node_Str";
              if (name.endsWith(end)) {
                nametruncate=name.lastIndexOf(end);
                player=p;
                LOGGER.trace("String_Node_Str");
                break;
              }
 else               if (getParent() != null && getParent().getName().endsWith(end)) {
                getParent().nametruncate=getParent().getName().lastIndexOf(end);
                player=p;
                LOGGER.trace("String_Node_Str");
                break;
              }
            }
          }
          if (player == null) {
            player=PlayerFactory.getPlayer(child);
          }
          if (player != null && !allChildrenAreFolders) {
            String configurationForceExtensions=configuration.getForceTranscodeForExtensions();
            String rendererForceExtensions=null;
            if (getDefaultRenderer() != null) {
              rendererForceExtensions=getDefaultRenderer().getTranscodedExtensions();
            }
            boolean forceTranscode=child.getFormat().skip(configurationForceExtensions,rendererForceExtensions);
            if (forceTranscode) {
              LOGGER.trace("String_Node_Str",child.getName());
            }
            boolean hasEmbeddedSubs=false;
            if (child.getMedia() != null) {
              for (              DLNAMediaSubtitle s : child.getMedia().getSubtitleTracksList()) {
                hasEmbeddedSubs=(hasEmbeddedSubs || s.isEmbedded());
              }
            }
            boolean hasSubsToTranscode=false;
            if (!configuration.isDisableSubtitles()) {
              if (configuration.isAutoloadExternalSubtitles() && child.isSubsFile()) {
                hasSubsToTranscode=child.getDefaultRenderer() != null && StringUtils.isBlank(child.getDefaultRenderer().getSupportedSubtitles());
              }
 else {
                hasSubsToTranscode=hasEmbeddedSubs;
              }
              if (hasSubsToTranscode) {
                LOGGER.trace("String_Node_Str",child.getName());
              }
            }
            boolean isIncompatible=false;
            if (!child.getFormat().isCompatible(child.getMedia(),getDefaultRenderer())) {
              isIncompatible=true;
              LOGGER.trace("String_Node_Str",child.getName());
            }
            boolean preferTranscode=isIncompatible || hasSubsToTranscode;
            if (forceTranscode || (preferTranscode && !isSkipTranscode())) {
              child.setPlayer(player);
              if (resumeRes != null) {
                resumeRes.setPlayer(player);
              }
              if (parserV2) {
                LOGGER.trace("String_Node_Str",child.getName(),player.toString(),child.getMedia().getMimeType());
              }
 else {
                LOGGER.trace("String_Node_Str",child.getName(),player.toString());
              }
            }
 else {
              LOGGER.trace("String_Node_Str",child.getName());
            }
            if ((child.getFormat().isVideo() || child.getFormat().isAudio()) && child.isTranscodeFolderAvailable()) {
              VirtualFolder transcodeFolder=getTranscodeFolder(true);
              if (transcodeFolder != null) {
                VirtualFolder fileTranscodeFolder=new FileTranscodeVirtualFolder(child.getDisplayName(),null);
                DLNAResource newChild=child.clone();
                newChild.setPlayer(player);
                newChild.setMedia(child.getMedia());
                fileTranscodeFolder.addChildInternal(newChild);
                LOGGER.trace("String_Node_Str",child.getName(),player.toString());
                transcodeFolder.addChild(fileTranscodeFolder);
              }
            }
            if (child.getFormat().isVideo() && child.isSubSelectable() && !(this instanceof SubSelFile)) {
              VirtualFolder vf=getSubSelector(true);
              if (vf != null) {
                DLNAResource newChild=child.clone();
                newChild.setPlayer(player);
                newChild.setMedia(child.getMedia());
                LOGGER.trace("String_Node_Str" + child.getName() + "String_Node_Str"+ player.toString());
                vf.addChild(new SubSelFile(newChild));
              }
            }
            for (            ExternalListener listener : ExternalFactory.getExternalListeners()) {
              if (listener instanceof AdditionalResourceFolderListener) {
                try {
                  ((AdditionalResourceFolderListener)listener).addAdditionalFolder(this,child);
                }
 catch (                Throwable t) {
                  LOGGER.error("String_Node_Str",listener.getClass(),t);
                }
              }
            }
          }
 else           if (!child.getFormat().isCompatible(child.getMedia(),getDefaultRenderer()) && !child.isFolder()) {
            LOGGER.trace("String_Node_Str",child.getName(),getDefaultRenderer().getRendererName());
            getChildren().remove(child);
          }
        }
        if (resumeRes != null) {
          resumeRes.setMedia(child.getMedia());
        }
        if (child.getFormat().getSecondaryFormat() != null && child.getMedia() != null && getDefaultRenderer() != null && getDefaultRenderer().supportsFormat(child.getFormat().getSecondaryFormat())) {
          DLNAResource newChild=child.clone();
          newChild.setFormat(newChild.getFormat().getSecondaryFormat());
          LOGGER.trace("String_Node_Str",newChild.getFormat().toString(),newChild.getName());
          newChild.first=child;
          child.second=newChild;
          if (!newChild.getFormat().isCompatible(newChild.getMedia(),getDefaultRenderer())) {
            Player player=PlayerFactory.getPlayer(newChild);
            newChild.setPlayer(player);
            LOGGER.trace("String_Node_Str",newChild.getFormat().toString(),child.getPlayer().name(),newChild.getName());
          }
          if (child.getMedia() != null && child.getMedia().isSecondaryFormatValid()) {
            addChild(newChild);
            LOGGER.trace("String_Node_Str",newChild.getFormat().toString(),newChild.getName());
          }
 else {
            LOGGER.trace("String_Node_Str",newChild.getFormat().toString(),newChild.getName());
          }
        }
      }
    }
  }
 catch (  Throwable t) {
    LOGGER.error("String_Node_Str",child.getName(),t);
    child.setParent(null);
    getChildren().remove(child);
  }
}

Fixed version (ground truth):
/** 
 * Adds a new DLNAResource to the child list. Only useful if this object is of the container type. <P> TODO: (botijo) check what happens with the child object. This function can and will transform the child object. If the transcode option is set, the child item is converted to a container with the real item and the transcode option folder. There is also a parser in order to get the right name and type, I suppose. Is this the right place to be doing things like these? <p> FIXME: Ideally the logic below is completely renderer-agnostic. Focus on harvesting generic data and transform it for a specific renderer as late as possible.
 * @param child DLNAResource to add to a container type.
 */
public void addChild(DLNAResource child){
  if (child == null) {
    LOGGER.error("String_Node_Str",getName());
    LOGGER.debug("String_Node_Str",new NullPointerException("String_Node_Str"));
    return;
  }
  child.setParent(this);
  child.setMasterParent(getMasterParent());
  if (getParent() != null) {
    setDefaultRenderer(getParent().getDefaultRenderer());
  }
  if (PMS.filter(getDefaultRenderer(),child)) {
    LOGGER.debug("String_Node_Str" + child.getName() + "String_Node_Str"+ getDefaultRenderer().getRendererName());
    return;
  }
  try {
    if (child.isValid()) {
      LOGGER.trace("String_Node_Str",child.getName(),child.getClass().getName());
      if (allChildrenAreFolders && !child.isFolder()) {
        allChildrenAreFolders=false;
      }
      child.resHash=Math.abs(child.getSystemName().hashCode() + resumeHash());
      DLNAResource resumeRes=null;
      ResumeObj r=ResumeObj.create(child);
      if (r != null) {
        resumeRes=child.clone();
        resumeRes.resume=r;
        resumeRes.resHash=child.resHash;
        addChildInternal(resumeRes);
      }
      addChildInternal(child);
      boolean parserV2=child.getMedia() != null && getDefaultRenderer() != null && getDefaultRenderer().isMediaParserV2();
      if (parserV2) {
        String mimeType=getDefaultRenderer().getFormatConfiguration().match(child.getMedia());
        if (mimeType != null) {
          if (!FormatConfiguration.MIMETYPE_AUTO.equals(mimeType)) {
            LOGGER.trace("String_Node_Str",child.getMedia().getMimeType(),child.getName(),mimeType);
            child.getMedia().setMimeType(mimeType);
          }
          LOGGER.trace("String_Node_Str",child.getName(),child.getMedia().getMimeType());
        }
 else {
          LOGGER.trace("String_Node_Str",child.getName());
        }
      }
      if (child.getFormat() != null) {
        String configurationSkipExtensions=configuration.getDisableTranscodeForExtensions();
        String rendererSkipExtensions=null;
        if (getDefaultRenderer() != null) {
          rendererSkipExtensions=getDefaultRenderer().getStreamedExtensions();
        }
        boolean skip=child.getFormat().skip(configurationSkipExtensions,rendererSkipExtensions);
        setSkipTranscode(skip);
        if (skip) {
          LOGGER.trace("String_Node_Str",child.getName());
        }
        if (parserV2 || (child.getFormat().transcodable() && child.getMedia() == null)) {
          if (!parserV2) {
            child.setMedia(new DLNAMediaInfo());
          }
          Player player=null;
          String name=getName();
          if (!configuration.isHideRecentlyPlayedFolder(null)) {
            player=child.getPlayer();
          }
 else {
            for (            Player p : PlayerFactory.getPlayers()) {
              String end="String_Node_Str" + p.id() + "String_Node_Str";
              if (name.endsWith(end)) {
                nametruncate=name.lastIndexOf(end);
                player=p;
                LOGGER.trace("String_Node_Str");
                break;
              }
 else               if (getParent() != null && getParent().getName().endsWith(end)) {
                getParent().nametruncate=getParent().getName().lastIndexOf(end);
                player=p;
                LOGGER.trace("String_Node_Str");
                break;
              }
            }
          }
          if (player == null) {
            player=PlayerFactory.getPlayer(child);
          }
          if (player != null && !allChildrenAreFolders) {
            String configurationForceExtensions=configuration.getForceTranscodeForExtensions();
            String rendererForceExtensions=null;
            if (getDefaultRenderer() != null) {
              rendererForceExtensions=getDefaultRenderer().getTranscodedExtensions();
            }
            boolean forceTranscode=child.getFormat().skip(configurationForceExtensions,rendererForceExtensions);
            if (forceTranscode) {
              LOGGER.trace("String_Node_Str",child.getName());
            }
            boolean hasEmbeddedSubs=false;
            if (child.getMedia() != null) {
              for (              DLNAMediaSubtitle s : child.getMedia().getSubtitleTracksList()) {
                hasEmbeddedSubs=(hasEmbeddedSubs || s.isEmbedded());
              }
            }
            boolean hasSubsToTranscode=false;
            if (!configuration.isDisableSubtitles()) {
              if (child.isSubsFile()) {
                hasSubsToTranscode=getDefaultRenderer() != null && StringUtils.isBlank(getDefaultRenderer().getSupportedSubtitles());
              }
 else {
                hasSubsToTranscode=hasEmbeddedSubs;
              }
              if (hasSubsToTranscode) {
                LOGGER.trace("String_Node_Str",child.getName());
              }
            }
            boolean isIncompatible=false;
            if (!child.getFormat().isCompatible(child.getMedia(),getDefaultRenderer())) {
              isIncompatible=true;
              LOGGER.trace("String_Node_Str",child.getName());
            }
            boolean preferTranscode=isIncompatible || hasSubsToTranscode;
            if (forceTranscode || (preferTranscode && !isSkipTranscode())) {
              child.setPlayer(player);
              if (resumeRes != null) {
                resumeRes.setPlayer(player);
              }
              if (parserV2) {
                LOGGER.trace("String_Node_Str",child.getName(),player.toString(),child.getMedia().getMimeType());
              }
 else {
                LOGGER.trace("String_Node_Str",child.getName(),player.toString());
              }
            }
 else {
              LOGGER.trace("String_Node_Str",child.getName());
            }
            if ((child.getFormat().isVideo() || child.getFormat().isAudio()) && child.isTranscodeFolderAvailable()) {
              VirtualFolder transcodeFolder=getTranscodeFolder(true);
              if (transcodeFolder != null) {
                VirtualFolder fileTranscodeFolder=new FileTranscodeVirtualFolder(child.getDisplayName(),null);
                DLNAResource newChild=child.clone();
                newChild.setPlayer(player);
                newChild.setMedia(child.getMedia());
                fileTranscodeFolder.addChildInternal(newChild);
                LOGGER.trace("String_Node_Str",child.getName(),player.toString());
                transcodeFolder.addChild(fileTranscodeFolder);
              }
            }
            if (child.getFormat().isVideo() && child.isSubSelectable() && !(this instanceof SubSelFile)) {
              VirtualFolder vf=getSubSelector(true);
              if (vf != null) {
                DLNAResource newChild=child.clone();
                newChild.setPlayer(player);
                newChild.setMedia(child.getMedia());
                LOGGER.trace("String_Node_Str" + child.getName() + "String_Node_Str"+ player.toString());
                vf.addChild(new SubSelFile(newChild));
              }
            }
            for (            ExternalListener listener : ExternalFactory.getExternalListeners()) {
              if (listener instanceof AdditionalResourceFolderListener) {
                try {
                  ((AdditionalResourceFolderListener)listener).addAdditionalFolder(this,child);
                }
 catch (                Throwable t) {
                  LOGGER.error("String_Node_Str",listener.getClass(),t);
                }
              }
            }
          }
 else           if (!child.getFormat().isCompatible(child.getMedia(),getDefaultRenderer()) && !child.isFolder()) {
            LOGGER.trace("String_Node_Str",child.getName(),getDefaultRenderer().getRendererName());
            getChildren().remove(child);
          }
        }
        if (resumeRes != null) {
          resumeRes.setMedia(child.getMedia());
        }
        if (child.getFormat().getSecondaryFormat() != null && child.getMedia() != null && getDefaultRenderer() != null && getDefaultRenderer().supportsFormat(child.getFormat().getSecondaryFormat())) {
          DLNAResource newChild=child.clone();
          newChild.setFormat(newChild.getFormat().getSecondaryFormat());
          LOGGER.trace("String_Node_Str",newChild.getFormat().toString(),newChild.getName());
          newChild.first=child;
          child.second=newChild;
          if (!newChild.getFormat().isCompatible(newChild.getMedia(),getDefaultRenderer())) {
            Player player=PlayerFactory.getPlayer(newChild);
            newChild.setPlayer(player);
            LOGGER.trace("String_Node_Str",newChild.getFormat().toString(),child.getPlayer().name(),newChild.getName());
          }
          if (child.getMedia() != null && child.getMedia().isSecondaryFormatValid()) {
            addChild(newChild);
            LOGGER.trace("String_Node_Str",newChild.getFormat().toString(),newChild.getName());
          }
 else {
            LOGGER.trace("String_Node_Str",newChild.getFormat().toString(),newChild.getName());
          }
        }
      }
    }
  }
 catch (  Throwable t) {
    LOGGER.error("String_Node_Str",child.getName(),t);
    child.setParent(null);
    getChildren().remove(child);
  }
}