001/*
002 * jPOS Project [http://jpos.org]
003 * Copyright (C) 2000-2026 jPOS Software SRL
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Affero General Public License as
007 * published by the Free Software Foundation, either version 3 of the
008 * License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
013 * GNU Affero General Public License for more details.
014 *
015 * You should have received a copy of the GNU Affero General Public License
016 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
017 */
018
019package org.jpos.util;
020import java.io.PrintStream;
021import java.util.regex.Pattern;
022
023/**
024 * Helpers for emitting strings that may contain XML-reserved characters
025 * inside log payloads, optionally wrapping them in {@code CDATA} blocks.
026 */
027public class LogUtil {
028    /** Utility class; instances carry no state. */
029    public LogUtil() {}
030    /** Regex matching XML-reserved characters that force CDATA escaping. */
031    public static final Pattern xmlReservedPattern = Pattern.compile("&|<|>");
032
033    /**
034     * Writes {@code s} to {@code p}, wrapping it in {@code <![CDATA[...]]>} when
035     * the string contains XML-reserved characters.
036     *
037     * @param p destination stream
038     * @param indent prefix used when the value is dumped on a single line
039     * @param s value to emit
040     */
041    public static void dump (PrintStream p, String indent, String s) {
042        try {
043            boolean expanded = s.length() > 60;
044            if (needsCDATA(s)) {
045                if (expanded) {
046                    p.println("<![CDATA[");
047                    p.println(s);
048                    p.println("]]>");
049                } else {
050                    p.print(indent + "<![CDATA[");
051                    p.print(s);
052                    p.println("]]>");
053                }
054            } else
055                p.print(s);
056        } catch (Exception e) {
057            p.println(e.getMessage());
058        }
059    }
060
061    /**
062     * Indicates whether {@code s} contains any XML-reserved characters and therefore
063     * needs {@code CDATA} escaping when embedded in XML output.
064     *
065     * @param s value to inspect
066     * @return {@code true} if any of {@code &}, {@code <}, or {@code >} is present
067     */
068    public static boolean needsCDATA(String s) {
069        return xmlReservedPattern.matcher(s).find();
070    }
071}