abstract class should be public to allow extension without having to repeat boilerplate methods