aboutsummaryrefslogtreecommitdiffstats
path: root/documentation/addons/chapter-addons.asciidoc
blob: dd432abdcc8ea6431f3027bf7a2147256f84e7fa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[[addons]]
== Using Vaadin Add-ons

This chapter describes the installation of add-on components, themes,
containers, and other tools from the Vaadin Directory and the use of commercial
add-ons offered by Vaadin.

include::addons-overview.asciidoc[leveloffset=+2]

include::addons-maven.asciidoc[leveloffset=+2]

include::addons-cval.asciidoc[leveloffset=+2]

// Outdated for the print edition
// include::addons-eclipse.asciidoc[leveloffset=+2]

// Irrelevant for the print edition
// include::addons-downloading.asciidoc[leveloffset=+2]

include::addons-troubleshooting.asciidoc[leveloffset=+2]
ground-color: #fff0f0 } /* Literal.String.Interpol */ .highlight .sx { color: #22bb22; background-color: #f0fff0 } /* Literal.String.Other */ .highlight .sr { color: #008800; background-color: #fff0ff } /* Literal.String.Regex */ .highlight .s1 { color: #dd2200; background-color: #fff0f0 } /* Literal.String.Single */ .highlight .ss { color: #aa6600; background-color: #fff0f0 } /* Literal.String.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
/*
 * Copyright 2021 gitblit.com, Ingo Lafrenz
 *
 * 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 com.gitblit;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.SortedMap;
import java.util.TreeMap;

/**
 * Simple class with the only purpose to save the realm file (users.conf) in
 * a fast efficient manner. The JGit Config classes used previously caused
 * a massive CPU hog if the users file got bigger than about 30000 lines.
 *
 * @author Ingo Lafrenz
 *
 */
public class StoredUserConfig {

	private final File realmFileCopy;
	private SortedMap<String, Section> sections = new TreeMap<>();

	public StoredUserConfig(File realmFileCopy) {
		this.realmFileCopy = realmFileCopy;
	}

	public void setString(final String section, final String subsection, String name, String value) {
		String key = generateKey(section, subsection);
		Section s = sections.get(key);
		if (s == null) {
			s = new Section(section, subsection);
			sections.put(key, s);
		}
		s.addEntry(name, value);
	}

	public void setBoolean(String section, String subsection, String name, boolean value) {
		setString(section, subsection, name, String.valueOf(value));
	}

	public void setStringList(String section, String subsection, String name, List<String> list) {
		for (String value : list) {
			setString(section, subsection, name, value);
		}
	}

	public void save() throws IOException {
		try (FileWriter fileWriter = new FileWriter(realmFileCopy);
				PrintWriter printWriter = new PrintWriter(fileWriter);) {
			for (Map.Entry<String,Section> entry : sections.entrySet()) {
				writeSection(printWriter, entry.getKey(), entry.getValue());
			}
		}
	}

	private static void writeSection(PrintWriter printWriter, String key, Section section) {
		if (section.getSubSection() == null) {
			printWriter.printf("[%s]\n", section.getName());
		}
		else {
			printWriter.printf("[%s \"%s\"]\n", section.getName(), section.getSubSection());
		}
		for (Entry entry : section.getEntries().values()) {
			writeEntry(printWriter, entry.getKey(), entry.getValue());
		}
	}

	private static void writeEntry(PrintWriter printWriter, String key, String value) {
		printWriter.printf("\t%s = %s\n", key, escape(value));
	}

	private static String escape(String value) {
		boolean quoteIt = false;
		StringBuilder fixedValue = new StringBuilder(value.length() + 20);

		for (char c : value.toCharArray()) {
			switch (c) {
				case '\n':
					fixedValue.append("\\n");
					break;

				case '\t':
					fixedValue.append("\\t");
					break;

				case '\b':
					fixedValue.append("\\b");
					break;

				case '\\':
					fixedValue.append("\\\\");
					break;

				case '"':
					fixedValue.append("\\\"");
					break;

				case ';':
				case '#':
					quoteIt = true;
					fixedValue.append(c);
					break;

				default:
					fixedValue.append(c);
					break;
			}
		}

		if (quoteIt) {
			fixedValue.insert(0,"\"");
			fixedValue.append("\"");
		}
		return fixedValue.toString();
	}

	private static String generateKey(String key, String subKey) {
		return "k:" + key + "s:" + (subKey == null ? "" : subKey);
	}

	private static class Section {
		private final String name;
		private final String subSection;
		private final SortedMap<String, Entry> entries = new TreeMap<>();

		public Section(String name, String subSection) {
			this.name = name;
			this.subSection = subSection;
		}

		public void addEntry(final String key, final String value) {
			entries.put(generateKey(key, value), new Entry(key, value));
		}

		public String getName() {
			return name;
		}

		public String getSubSection() {
			return subSection;
		}

		public SortedMap<String, Entry> getEntries() {
			return entries;
		}

		@Override
		public int hashCode() {
			return Objects.hash(name, subSection);
		}

		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			Section other = (Section) obj;
			return Objects.equals(name, other.name) && Objects.equals(subSection, other.subSection);
		}

		@Override
		public String toString() {
			return String.format("Section [name=%s, subSection=%s]", name, subSection);
		}

	}

	private static class Entry {
		private final String key;
		private final String value;

		public Entry(String key, String value) {
			this.key = key;
			this.value = value;
		}

		public String getKey() {
			return key;
		}

		public String getValue() {
			return value;
		}

		@Override
		public int hashCode() {
			return Objects.hash(key, value);
		}

		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			Entry other = (Entry) obj;
			return Objects.equals(key, other.key) && Objects.equals(value, other.value);
		}

		@Override
		public String toString() {
			return String.format("Entry [key=%s, value=%s]", key, value);
		}

	}

}